MUTTER_MIN_VERSION=2.91.90
GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.25.9
-LIBECAL_REQUIRED=1.6.0
-LIBEDATASERVER_REQUIRED=1.2.0
-LIBEDATASERVERUI2_REQUIRED=1.2.0
-LIBEDATASERVERUI3_REQUIRED=2.91.6
+LIBECAL_MIN_VERSION=1.6.0
+LIBEDATASERVER_MIN_VERSION=1.2.0
+LIBEDATASERVERUI2_MIN_VERSION=1.2.0
+LIBEDATASERVERUI3_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.13.12
POLKIT_MIN_VERSION=0.100
# Default to libedataserverui-3.0, but allow falling back to 1.2
PKG_CHECK_EXISTS(libedataserverui-3.0,
[EDS_API=3.0
- LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
+ LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
[EDS_API=1.2
- LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
-PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
-AC_SUBST(LIBECAL_CFLAGS)
-AC_SUBST(LIBECAL_LIBS)
+ LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
+PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
+AC_SUBST(CALENDAR_SERVER_CFLAGS)
+AC_SUBST(CALENDAR_SERVER_LIBS)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
# FIXME: metacity-plugins.pc should point directly to its .gir file
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+const DBus = imports.dbus;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
// Abstraction for an appointment/event in a calendar
-function CalendarEvent(date, summary, allDay) {
- this._init(date, summary, allDay);
+function CalendarEvent(date, end, summary, allDay) {
+ this._init(date, end, summary, allDay);
}
CalendarEvent.prototype = {
- _init: function(date, summary, allDay) {
+ _init: function(date, end, summary, allDay) {
this.date = date;
+ this.end = end;
this.summary = summary;
this.allDay = allDay;
}
};
Signals.addSignalMethods(EmptyEventSource.prototype);
-// Second, wrap native Evolution event source
-function EvolutionEventSource() {
+const CalendarServerIface = {
+ name: 'org.gnome.Shell.CalendarServer',
+ methods: [{ name: 'GetEvents',
+ inSignature: 'xxb',
+ outSignature: 'a(sssbxxa{sv})' }],
+ signals: [{ name: 'Changed',
+ inSignature: '' }]
+};
+
+const CalendarServer = function () {
this._init();
-}
+};
-EvolutionEventSource.prototype = {
- _init: function() {
- this._native = new Shell.EvolutionEventSource();
- this._native.connect('changed', Lang.bind(this, function() {
- this.emit('changed');
- }));
- },
+CalendarServer.prototype = {
+ _init: function() {
+ DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
+ }
+};
- requestRange: function(begin, end) {
- this._native.request_range(begin.getTime(), end.getTime());
- },
+DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
- getEvents: function(begin, end) {
- let result = [];
- let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
- for (let n = 0; n < nativeEvents.length; n++) {
- let nativeEvent = nativeEvents[n];
- result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
- }
- return result;
- },
+// an implementation that reads data from a session bus service
+function DBusEventSource(owner) {
+ this._init(owner);
+}
- hasEvents: function(day) {
- let dayBegin = _getBeginningOfDay(day);
- let dayEnd = _getEndOfDay(day);
+function _datesEqual(a, b) {
+ if (a < b)
+ return false;
+ else if (a > b)
+ return false;
+ return true;
+}
- let events = this.getEvents(dayBegin, dayEnd);
+function _dateIntervalsOverlap(a0, a1, b0, b1)
+{
+ if (a1 <= b0)
+ return false;
+ else if (b1 <= a0)
+ return false;
+ else
+ return true;
+}
- if (events.length == 0)
- return false;
- return true;
- }
-};
-Signals.addSignalMethods(EvolutionEventSource.prototype);
+DBusEventSource.prototype = {
+ _init: function(owner) {
+ this._resetCache();
-// Finally, an implementation with fake events
-function FakeEventSource() {
- this._init();
-}
+ this._dbusProxy = new CalendarServer(owner);
+ this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
-FakeEventSource.prototype = {
- _init: function() {
+ DBus.session.watch_name('org.gnome.Shell.CalendarServer',
+ false, // do not launch a name-owner if none exists
+ Lang.bind(this, this._onNameAppeared),
+ Lang.bind(this, this._onNameVanished));
+ },
- this._fakeEvents = [];
+ _resetCache: function() {
+ this._events = [];
+ this._lastRequestBegin = null;
+ this._lastRequestEnd = null;
+ },
- // Generate fake events
- //
- let midnightToday = _getBeginningOfDay(new Date());
- let summary = '';
-
- // '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
- for (let n = 0; n < 10; n++) {
- let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
- t.setHours(10);
- summary = '10-oclock pow-wow (n=' + n + ')';
- this._fakeEvents.push(new CalendarEvent(t, summary, false));
- }
+ _onNameAppeared: function(owner) {
+ this._resetCache();
+ this._loadEvents(true);
+ },
- // '11-oclock thing' is an event occuring every three days at 11am
- for (let n = 0; n < 10; n++) {
- let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
- t.setHours(11);
- summary = '11-oclock thing (n=' + n + ')';
- this._fakeEvents.push(new CalendarEvent(t, summary, false));
- }
+ _onNameVanished: function(oldOwner) {
+ this._resetCache();
+ this.emit('changed');
+ },
- // 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
- for (let n = 0; n < 5; n++) {
- let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
- t.setHours(13);
- t.setMinutes(45);
- summary = 'Weekly Meeting (n=' + n + ')';
- this._fakeEvents.push(new CalendarEvent(t, summary, false));
- }
+ _onChanged: function() {
+ this._loadEvents(false);
+ },
- // 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
- for (let n = 0; n < 10; n++) {
- let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
- summary = 'Fun All Day (n=' + n + ')';
- this._fakeEvents.push(new CalendarEvent(t, summary, true));
+ _onEventsReceived: function(appointments) {
+ let newEvents = [];
+ if (appointments != null) {
+ for (let n = 0; n < appointments.length; n++) {
+ let a = appointments[n];
+ let date = new Date(a[4] * 1000);
+ let end = new Date(a[5] * 1000);
+ let summary = a[1];
+ let allDay = a[3];
+ let event = new CalendarEvent(date, end, summary, allDay);
+ newEvents.push(event);
+ }
+ newEvents.sort(function(event1, event2) {
+ return event1.date.getTime() - event2.date.getTime();
+ });
}
- // 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
- this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
-
- // ditto for 'NE Patriots vs NY Jets'
- this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
-
- // An event for tomorrow @6:30pm that is added/removed every five
- // seconds (to check that the ::changed signal works)
- let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
- transientEventDate.setHours(18);
- transientEventDate.setMinutes(30);
- transientEventDate.setSeconds(0);
- Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
- this._includeTransientEvent = false;
- this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
- this._transientEventCounter = 1;
+ this._events = newEvents;
+ this.emit('changed');
},
- _updateTransientEvent: function() {
- this._includeTransientEvent = !this._includeTransientEvent;
- this._transientEventCounter = this._transientEventCounter + 1;
- this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
- this.emit('changed');
- Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
+ _loadEvents: function(forceReload) {
+ if (this._curRequestBegin && this._curRequestEnd){
+ let callFlags = 0;
+ if (forceReload)
+ callFlags |= DBus.CALL_FLAG_START;
+ this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
+ this._curRequestEnd.getTime() / 1000,
+ forceReload,
+ Lang.bind(this, this._onEventsReceived),
+ callFlags);
+ }
},
- requestRange: function(begin, end) {
+ requestRange: function(begin, end, forceReload) {
+ if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
+ this._lastRequestBegin = begin;
+ this._lastRequestEnd = end;
+ this._curRequestBegin = begin;
+ this._curRequestEnd = end;
+ this._loadEvents(forceReload);
+ }
},
getEvents: function(begin, end) {
let result = [];
- //log('begin:' + begin);
- //log('end: ' + end);
- for(let n = 0; n < this._fakeEvents.length; n++) {
- let event = this._fakeEvents[n];
- if (event.date >= begin && event.date <= end) {
+ for(let n = 0; n < this._events.length; n++) {
+ let event = this._events[n];
+ if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
result.push(event);
}
- //log('when:' + event.date + ' summary:' + event.summary);
}
- if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
- result.push(this._transientEvent);
- result.sort(function(event1, event2) {
- return event1.date.getTime() - event2.date.getTime();
- });
return result;
},
return true;
}
-
};
-Signals.addSignalMethods(FakeEventSource.prototype);
+Signals.addSignalMethods(DBusEventSource.prototype);
// Calendar:
// @eventSource: is an object implementing the EventSource API, e.g. the
_init: function(eventSource) {
this._eventSource = eventSource;
- this._eventSource.connect('changed', Lang.bind(this, this._update));
+ this._eventSource.connect('changed', Lang.bind(this,
+ function() {
+ this._update(false);
+ }));
// FIXME: This is actually the fallback method for GTK+ for the week start;
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
Lang.bind(this, this._onScroll));
this._buildHeader ();
- this._update();
},
// Sets the calendar to show a specific date
- setDate: function(date) {
+ setDate: function(date, forceReload) {
if (!_sameDay(date, this._selectedDate)) {
this._selectedDate = date;
- this._update();
+ this._update(forceReload);
this.emit('selected-date-changed', new Date(this._selectedDate));
+ } else {
+ if (forceReload)
+ this._update(forceReload);
}
},
}
}
- this.setDate(newDate);
+ this.setDate(newDate, false);
},
_onNextMonthButtonClicked: function() {
}
}
- this.setDate(newDate);
+ this.setDate(newDate, false);
},
_onSettingsChange: function() {
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader();
- this._update();
+ this._update(false);
},
- _update: function() {
+ _update: function(forceReload) {
let now = new Date();
if (_sameYear(this._selectedDate, now))
let iterStr = iter.toUTCString();
button.connect('clicked', Lang.bind(this, function() {
let newlySelectedDate = new Date(iterStr);
- this.setDate(newlySelectedDate);
+ this.setDate(newlySelectedDate, false);
}));
let hasEvents = this._eventSource.hasEvents(iter);
}
// Signal to the event source that we are interested in events
// only from this date range
- this._eventSource.requestRange(beginDate, iter);
+ this._eventSource.requestRange(beginDate, iter, forceReload);
}
};
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
- let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
+ let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
}
let hbox;
let vbox;
- //this._eventSource = new Calendar.EmptyEventSource();
- //this._eventSource = new Calendar.FakeEventSource();
- this._eventSource = new Calendar.EvolutionEventSource();
+ this._eventSource = new Calendar.DBusEventSource();
let menuAlignment = 0.25;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
if (isOpen) {
let now = new Date();
- this._calendar.setDate(now);
+ /* Passing true to setDate() forces events to be reloaded. We
+ * want this behavior, because
+ *
+ * o It will cause activation of the calendar server which is
+ * useful if it has crashed
+ *
+ * o It will cause the calendar server to reload events which
+ * is useful if dynamic updates are not supported or not
+ * properly working
+ *
+ * Since this only happens when the menu is opened, the cost
+ * isn't very big.
+ */
+ this._calendar.setDate(now, true);
// No need to update this._eventList as ::selected-date-changed
// signal will fire
}
// back into sync ones.
DBus.session.flush();
+ // Load the calendar server. Note that we are careful about
+ // not loading any events until the user presses the clock
+ global.launch_calendar_server();
+
Environment.init();
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
+++ /dev/null
-
-noinst_LTLIBRARIES += libcalendar-client.la
-
-libcalendar_client_la_SOURCES = \
- calendar-client/calendar-client.h calendar-client/calendar-client.c \
- calendar-client/calendar-debug.h \
- calendar-client/calendar-sources.c calendar-client/calendar-sources.h \
- $(NULL)
-
-libcalendar_client_la_CFLAGS = \
- -I$(top_srcdir)/src \
- -DPREFIX=\""$(prefix)"\" \
- -DLIBDIR=\""$(libdir)"\" \
- -DDATADIR=\""$(datadir)"\" \
- -DG_DISABLE_DEPRECATED \
- -DG_LOG_DOMAIN=\"CalendarClient\" \
- $(LIBECAL_CFLAGS) \
- $(NULL)
-
-libcalendar_client_la_LIBADD = $(LIBECAL_LIBS)
-
-EXTRA_DIST += calendar-client/README
--- /dev/null
+
+servicedir = $(datadir)/dbus-1/services
+service_in_files = calendar-server/org.gnome.Shell.CalendarServer.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@.tmp && mv $@.tmp $@
+
+libexec_PROGRAMS += gnome-shell-calendar-server
+
+gnome_shell_calendar_server_SOURCES = \
+ calendar-server/calendar-debug.h \
+ calendar-server/calendar-sources.c calendar-server/calendar-sources.h \
+ calendar-server/gnome-shell-calendar-server.c \
+ $(NULL)
+
+gnome_shell_calendar_server_CFLAGS = \
+ -I$(top_srcdir)/src \
+ -DPREFIX=\""$(prefix)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DG_LOG_DOMAIN=\"ShellCalendarServer\" \
+ $(CALENDAR_SERVER_CFLAGS) \
+ $(NULL)
+
+gnome_shell_calendar_server_LDFLAGS = \
+ $(CALENDAR_SERVER_LIBS) \
+ $(NULL)
+
+EXTRA_DIST += \
+ calendar-server/README \
+ calendar-server/org.gnome.Shell.CalendarServer.service.in \
+ $(NULL)
include Makefile-st.am
include Makefile-tray.am
include Makefile-gvc.am
-include Makefile-calendar-client.am
+include Makefile-calendar-server.am
gnome_shell_cflags = \
$(MUTTER_PLUGIN_CFLAGS) \
$(LIBGNOMEUI_CFLAGS) \
-I$(srcdir)/tray \
-DLOCALEDIR=\"$(datadir)/locale\" \
+ -DGNOME_SHELL_LIBEXECDIR=\"$(libexecdir)\" \
-DGNOME_SHELL_DATADIR=\"$(pkgdatadir)\" \
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
-DJSDIR=\"$(pkgdatadir)/js\"
shell-arrow.c \
shell-doc-system.c \
shell-embedded-window.c \
- shell-evolution-event-source.h \
- shell-evolution-event-source.c \
shell-generic-container.c \
shell-gtk-embed.c \
shell-global.c \
libgdmuser-1.0.la \
libtray.la \
libgvc.la \
- libcalendar-client.la \
$(NULL)
-libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
+libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags) $(LIBECAL_CFLAGS)
typelibdir = $(pkglibdir)
typelib_DATA = Shell-0.1.typelib St-1.0.typelib Gdm-1.0.typelib Gvc-1.0.typelib
+++ /dev/null
-Please keep in sync with gnome-panel.
+++ /dev/null
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- * Mark McLoughlin <mark@skynet.ie>
- * William Jon McCann <mccann@jhu.edu>
- * Martin Grimme <martin@pycage.de>
- * Christian Kellner <gicmo@xatom.net>
- */
-
-#include <config.h>
-
-#include "calendar-client.h"
-
-#include <libintl.h>
-#include <string.h>
-#define HANDLE_LIBICAL_MEMORY
-#include <libecal/e-cal.h>
-#include <libecal/e-cal-time-util.h>
-#include <libecal/e-cal-recur.h>
-
-#include "calendar-sources.h"
-
-#undef CALENDAR_ENABLE_DEBUG
-#include "calendar-debug.h"
-
-#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
-#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
-
-#ifndef _
-#define _(x) gettext(x)
-#endif
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-#define CALENDAR_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_CLIENT, CalendarClientPrivate))
-
-typedef struct _CalendarClientQuery CalendarClientQuery;
-typedef struct _CalendarClientSource CalendarClientSource;
-
-struct _CalendarClientQuery
-{
- ECalView *view;
- GHashTable *events;
-};
-
-struct _CalendarClientSource
-{
- CalendarClient *client;
- ECal *source;
-
- CalendarClientQuery completed_query;
- CalendarClientQuery in_progress_query;
-
- guint changed_signal_id;
-
- guint query_completed : 1;
- guint query_in_progress : 1;
-};
-
-struct _CalendarClientPrivate
-{
- CalendarSources *calendar_sources;
-
- GSList *appointment_sources;
- GSList *task_sources;
-
- icaltimezone *zone;
-
- guint zone_listener;
- GConfClient *gconf_client;
-
- guint day;
- guint month;
- guint year;
-};
-
-static void calendar_client_class_init (CalendarClientClass *klass);
-static void calendar_client_init (CalendarClient *client);
-static void calendar_client_finalize (GObject *object);
-static void calendar_client_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void calendar_client_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-static GSList *calendar_client_update_sources_list (CalendarClient *client,
- GSList *sources,
- GSList *esources,
- guint changed_signal_id);
-static void calendar_client_appointment_sources_changed (CalendarClient *client);
-static void calendar_client_task_sources_changed (CalendarClient *client);
-
-static void calendar_client_stop_query (CalendarClient *client,
- CalendarClientSource *source,
- CalendarClientQuery *query);
-static void calendar_client_start_query (CalendarClient *client,
- CalendarClientSource *source,
- const char *query);
-
-static void calendar_client_source_finalize (CalendarClientSource *source);
-static void calendar_client_query_finalize (CalendarClientQuery *query);
-
-static void
-calendar_client_update_appointments (CalendarClient *client);
-static void
-calendar_client_update_tasks (CalendarClient *client);
-
-enum
-{
- PROP_O,
- PROP_DAY,
- PROP_MONTH,
- PROP_YEAR
-};
-
-enum
-{
- APPOINTMENTS_CHANGED,
- TASKS_CHANGED,
- LAST_SIGNAL
-};
-
-static GObjectClass *parent_class = NULL;
-static guint signals [LAST_SIGNAL] = { 0, };
-
-GType
-calendar_client_get_type (void)
-{
- static GType client_type = 0;
-
- if (!client_type)
- {
- static const GTypeInfo client_info =
- {
- sizeof (CalendarClientClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) calendar_client_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (CalendarClient),
- 0, /* n_preallocs */
- (GInstanceInitFunc) calendar_client_init,
- };
-
- client_type = g_type_register_static (G_TYPE_OBJECT,
- "CalendarClient",
- &client_info, 0);
- }
-
- return client_type;
-}
-
-static void
-calendar_client_class_init (CalendarClientClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = calendar_client_finalize;
- gobject_class->set_property = calendar_client_set_property;
- gobject_class->get_property = calendar_client_get_property;
-
- g_type_class_add_private (klass, sizeof (CalendarClientPrivate));
-
- g_object_class_install_property (gobject_class,
- PROP_DAY,
- g_param_spec_uint ("day",
- "Day",
- "The currently monitored day between 1 and 31 (0 denotes unset)",
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class,
- PROP_MONTH,
- g_param_spec_uint ("month",
- "Month",
- "The currently monitored month between 0 and 11",
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class,
- PROP_YEAR,
- g_param_spec_uint ("year",
- "Year",
- "The currently monitored year",
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE));
-
- signals [APPOINTMENTS_CHANGED] =
- g_signal_new ("appointments-changed",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- signals [TASKS_CHANGED] =
- g_signal_new ("tasks-changed",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-}
-
-/* Timezone code adapted from evolution/calendar/gui/calendar-config.c */
-/* The current timezone, e.g. "Europe/London". It may be NULL, in which case
- you should assume UTC. */
-static gchar *
-calendar_client_config_get_timezone (GConfClient *gconf_client)
-{
- char *location;
-
- location = gconf_client_get_string (gconf_client,
- CALENDAR_CONFIG_TIMEZONE,
- NULL);
-
- return location;
-}
-
-static icaltimezone *
-calendar_client_config_get_icaltimezone (GConfClient *gconf_client)
-{
- char *location;
- icaltimezone *zone = NULL;
-
- location = calendar_client_config_get_timezone (gconf_client);
- if (!location)
- return icaltimezone_get_utc_timezone ();
-
- zone = icaltimezone_get_builtin_timezone (location);
- g_free (location);
-
- return zone;
-}
-
-static void
-calendar_client_set_timezone (CalendarClient *client)
-{
- GSList *l;
- GSList *esources;
-
- client->priv->zone = calendar_client_config_get_icaltimezone (client->priv->gconf_client);
-
- esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
- for (l = esources; l; l = l->next) {
- ECal *source = l->data;
-
- e_cal_set_default_timezone (source, client->priv->zone, NULL);
- }
-}
-
-static void
-calendar_client_timezone_changed_cb (GConfClient *gconf_client,
- guint id,
- GConfEntry *entry,
- CalendarClient *client)
-{
- calendar_client_set_timezone (client);
-}
-
-static void
-cal_opened_cb (ECal *ecal,
- ECalendarStatus status,
- CalendarClientSource *cl_source)
-{
- ECalSourceType s_type;
- CalendarClient *client = cl_source->client;
-
- s_type = e_cal_get_source_type (ecal);
-
- if (status == E_CALENDAR_STATUS_BUSY &&
- e_cal_get_load_state (ecal) == E_CAL_LOAD_NOT_LOADED)
- {
- e_cal_open_async (ecal, FALSE);
- return;
- }
-
- g_signal_handlers_disconnect_by_func (ecal, cal_opened_cb, cl_source);
-
- if (status != E_CALENDAR_STATUS_OK)
- {
- if (s_type == E_CAL_SOURCE_TYPE_EVENT)
- client->priv->appointment_sources = g_slist_remove (client->priv->appointment_sources,
- cl_source);
- else
- client->priv->task_sources = g_slist_remove (client->priv->task_sources,
- cl_source);
-
- calendar_client_source_finalize (cl_source);
- g_free (cl_source);
-
- return;
- }
-
- if (s_type == E_CAL_SOURCE_TYPE_EVENT)
- calendar_client_update_appointments (client);
- else
- calendar_client_update_tasks (client);
-}
-
-static void
-load_calendars (CalendarClient *client,
- CalendarEventType type)
-{
- GSList *l, *clients;
-
- switch (type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- clients = client->priv->appointment_sources;
- break;
- case CALENDAR_EVENT_TASK:
- clients = client->priv->task_sources;
- break;
- default:
- g_assert_not_reached ();
- }
-
- for (l = clients; l != NULL; l = l->next)
- {
- ECal *ecal;
- CalendarClientSource *cl_source = l->data;
-
- ecal = cl_source->source;
-
- if (e_cal_get_load_state (ecal) == E_CAL_LOAD_LOADED)
- continue;
-
- g_signal_connect (G_OBJECT (ecal), "cal_opened",
- G_CALLBACK (cal_opened_cb), cl_source);
- e_cal_open_async (ecal, TRUE);
- }
-}
-
-static void
-calendar_client_init (CalendarClient *client)
-{
- GSList *esources;
-
- client->priv = CALENDAR_CLIENT_GET_PRIVATE (client);
-
- client->priv->calendar_sources = calendar_sources_get ();
- client->priv->gconf_client = gconf_client_get_default ();
-
- esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
- client->priv->appointment_sources =
- calendar_client_update_sources_list (client, NULL, esources, signals [APPOINTMENTS_CHANGED]);
-
- esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
- client->priv->task_sources =
- calendar_client_update_sources_list (client, NULL, esources, signals [TASKS_CHANGED]);
-
- /* set the timezone before loading the clients */
- calendar_client_set_timezone (client);
- load_calendars (client, CALENDAR_EVENT_APPOINTMENT);
- load_calendars (client, CALENDAR_EVENT_TASK);
-
- g_signal_connect_swapped (client->priv->calendar_sources,
- "appointment-sources-changed",
- G_CALLBACK (calendar_client_appointment_sources_changed),
- client);
- g_signal_connect_swapped (client->priv->calendar_sources,
- "task-sources-changed",
- G_CALLBACK (calendar_client_task_sources_changed),
- client);
-
- gconf_client_add_dir (client->priv->gconf_client,
- CALENDAR_CONFIG_PREFIX,
- GCONF_CLIENT_PRELOAD_NONE,
- NULL);
-
- client->priv->zone_listener = gconf_client_notify_add (client->priv->gconf_client,
- CALENDAR_CONFIG_TIMEZONE,
- (GConfClientNotifyFunc) calendar_client_timezone_changed_cb,
- client, NULL, NULL);
-
- client->priv->day = -1;
- client->priv->month = -1;
- client->priv->year = -1;
-}
-
-static void
-calendar_client_finalize (GObject *object)
-{
- CalendarClient *client = CALENDAR_CLIENT (object);
- GSList *l;
-
- if (client->priv->zone_listener)
- {
- gconf_client_notify_remove (client->priv->gconf_client,
- client->priv->zone_listener);
- client->priv->zone_listener = 0;
- }
-
- gconf_client_remove_dir (client->priv->gconf_client,
- CALENDAR_CONFIG_PREFIX,
- NULL);
-
- if (client->priv->gconf_client)
- g_object_unref (client->priv->gconf_client);
- client->priv->gconf_client = NULL;
-
- for (l = client->priv->appointment_sources; l; l = l->next)
- {
- calendar_client_source_finalize (l->data);
- g_free (l->data);
- }
- g_slist_free (client->priv->appointment_sources);
- client->priv->appointment_sources = NULL;
-
- for (l = client->priv->task_sources; l; l = l->next)
- {
- calendar_client_source_finalize (l->data);
- g_free (l->data);
- }
- g_slist_free (client->priv->task_sources);
- client->priv->task_sources = NULL;
-
- if (client->priv->calendar_sources)
- g_object_unref (client->priv->calendar_sources);
- client->priv->calendar_sources = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-calendar_client_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- CalendarClient *client = CALENDAR_CLIENT (object);
-
- switch (prop_id)
- {
- case PROP_DAY:
- calendar_client_select_day (client, g_value_get_uint (value));
- break;
- case PROP_MONTH:
- calendar_client_select_month (client,
- g_value_get_uint (value),
- client->priv->year);
- break;
- case PROP_YEAR:
- calendar_client_select_month (client,
- client->priv->month,
- g_value_get_uint (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-calendar_client_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- CalendarClient *client = CALENDAR_CLIENT (object);
-
- switch (prop_id)
- {
- case PROP_DAY:
- g_value_set_uint (value, client->priv->day);
- break;
- case PROP_MONTH:
- g_value_set_uint (value, client->priv->month);
- break;
- case PROP_YEAR:
- g_value_set_uint (value, client->priv->year);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-CalendarClient *
-calendar_client_new (void)
-{
- return g_object_new (CALENDAR_TYPE_CLIENT, NULL);
-}
-
-/* @day and @month can happily be out of range as
- * mktime() will normalize them correctly. From mktime(3):
- *
- * "If structure members are outside their legal interval,
- * they will be normalized (so that, e.g., 40 October is
- * changed into 9 November)."
- *
- * "What?", you say, "Something useful in libc?"
- */
-static inline time_t
-make_time_for_day_begin (int day,
- int month,
- int year)
-{
- struct tm localtime_tm = { 0, };
-
- localtime_tm.tm_mday = day;
- localtime_tm.tm_mon = month;
- localtime_tm.tm_year = year - 1900;
- localtime_tm.tm_isdst = -1;
-
- return mktime (&localtime_tm);
-}
-
-static inline char *
-make_isodate_for_day_begin (int day,
- int month,
- int year)
-{
- time_t utctime;
-
- utctime = make_time_for_day_begin (day, month, year);
-
- return utctime != -1 ? isodate_from_time_t (utctime) : NULL;
-}
-
-static time_t
-get_time_from_property (icalcomponent *ical,
- icalproperty_kind prop_kind,
- struct icaltimetype (* get_prop_func) (const icalproperty *prop),
- icaltimezone *default_zone)
-{
- icalproperty *prop;
- struct icaltimetype ical_time;
- icalparameter *param;
- icaltimezone *timezone = NULL;
-
- prop = icalcomponent_get_first_property (ical, prop_kind);
- if (!prop)
- return 0;
-
- ical_time = get_prop_func (prop);
-
- param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
- if (param)
- timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
- else if (icaltime_is_utc (ical_time))
- timezone = icaltimezone_get_utc_timezone ();
- else
- timezone = default_zone;
-
- return icaltime_as_timet_with_zone (ical_time, timezone);
-}
-
-static char *
-get_ical_uid (icalcomponent *ical)
-{
- return g_strdup (icalcomponent_get_uid (ical));
-}
-
-static char *
-get_ical_rid (icalcomponent *ical)
-{
- icalproperty *prop;
- struct icaltimetype ical_time;
-
- prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
- if (!prop)
- return NULL;
-
- ical_time = icalproperty_get_recurrenceid (prop);
-
- return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ?
- g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
-}
-
-static char *
-get_ical_summary (icalcomponent *ical)
-{
- icalproperty *prop;
-
- prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
- if (!prop)
- return NULL;
-
- return g_strdup (icalproperty_get_summary (prop));
-}
-
-static char *
-get_ical_description (icalcomponent *ical)
-{
- icalproperty *prop;
-
- prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
- if (!prop)
- return NULL;
-
- return g_strdup (icalproperty_get_description (prop));
-}
-
-static inline time_t
-get_ical_start_time (icalcomponent *ical,
- icaltimezone *default_zone)
-{
- return get_time_from_property (ical,
- ICAL_DTSTART_PROPERTY,
- icalproperty_get_dtstart,
- default_zone);
-}
-
-static inline time_t
-get_ical_end_time (icalcomponent *ical,
- icaltimezone *default_zone)
-{
- return get_time_from_property (ical,
- ICAL_DTEND_PROPERTY,
- icalproperty_get_dtend,
- default_zone);
-}
-
-static gboolean
-get_ical_is_all_day (icalcomponent *ical,
- time_t start_time,
- icaltimezone *default_zone)
-{
- icalproperty *prop;
- struct tm *start_tm;
- time_t end_time;
- struct icaldurationtype duration;
- struct icaltimetype start_icaltime;
-
- start_icaltime = icalcomponent_get_dtstart (ical);
- if (start_icaltime.is_date)
- return TRUE;
-
- start_tm = gmtime (&start_time);
- if (start_tm->tm_sec != 0 ||
- start_tm->tm_min != 0 ||
- start_tm->tm_hour != 0)
- return FALSE;
-
- if ((end_time = get_ical_end_time (ical, default_zone)))
- return (end_time - start_time) % 86400 == 0;
-
- prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
- if (!prop)
- return FALSE;
-
- duration = icalproperty_get_duration (prop);
-
- return icaldurationtype_as_int (duration) % 86400 == 0;
-}
-
-static inline time_t
-get_ical_due_time (icalcomponent *ical,
- icaltimezone *default_zone)
-{
- return get_time_from_property (ical,
- ICAL_DUE_PROPERTY,
- icalproperty_get_due,
- default_zone);
-}
-
-static guint
-get_ical_percent_complete (icalcomponent *ical)
-{
- icalproperty *prop;
- icalproperty_status status;
- int percent_complete;
-
- status = icalcomponent_get_status (ical);
- if (status == ICAL_STATUS_COMPLETED)
- return 100;
-
- prop = icalcomponent_get_first_property (ical, ICAL_COMPLETED_PROPERTY);
- if (prop)
- return 100;
-
- prop = icalcomponent_get_first_property (ical, ICAL_PERCENTCOMPLETE_PROPERTY);
- if (!prop)
- return 0;
-
- percent_complete = icalproperty_get_percentcomplete (prop);
-
- return CLAMP (percent_complete, 0, 100);
-}
-
-static inline time_t
-get_ical_completed_time (icalcomponent *ical,
- icaltimezone *default_zone)
-{
- return get_time_from_property (ical,
- ICAL_COMPLETED_PROPERTY,
- icalproperty_get_completed,
- default_zone);
-}
-
-static int
-get_ical_priority (icalcomponent *ical)
-{
- icalproperty *prop;
-
- prop = icalcomponent_get_first_property (ical, ICAL_PRIORITY_PROPERTY);
- if (!prop)
- return -1;
-
- return icalproperty_get_priority (prop);
-}
-
-static char *
-get_source_color (ECal *esource)
-{
- ESource *source;
-
- g_return_val_if_fail (E_IS_CAL (esource), NULL);
-
- source = e_cal_get_source (esource);
-
- return g_strdup (e_source_peek_color_spec (source));
-}
-
-static gchar *
-get_source_uri (ECal *esource)
-{
- ESource *source;
- gchar *string;
- gchar **list;
-
- g_return_val_if_fail (E_IS_CAL (esource), NULL);
-
- source = e_cal_get_source (esource);
- string = g_strdup (e_source_get_uri (source));
- if (string) {
- list = g_strsplit (string, ":", 2);
- g_free (string);
-
- if (list[0]) {
- string = g_strdup (list[0]);
- g_strfreev (list);
- return string;
- }
- g_strfreev (list);
- }
- return NULL;
-}
-
-static inline int
-null_safe_strcmp (const char *a,
- const char *b)
-{
- return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
-}
-
-static inline gboolean
-calendar_appointment_equal (CalendarAppointment *a,
- CalendarAppointment *b)
-{
- GSList *la, *lb;
-
- if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
- return FALSE;
-
- for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
- {
- CalendarOccurrence *oa = la->data;
- CalendarOccurrence *ob = lb->data;
-
- if (oa->start_time != ob->start_time ||
- oa->end_time != ob->end_time)
- return FALSE;
- }
-
- return
- null_safe_strcmp (a->uid, b->uid) == 0 &&
- null_safe_strcmp (a->uri, b->uri) == 0 &&
- null_safe_strcmp (a->summary, b->summary) == 0 &&
- null_safe_strcmp (a->description, b->description) == 0 &&
- null_safe_strcmp (a->color_string, b->color_string) == 0 &&
- a->start_time == b->start_time &&
- a->end_time == b->end_time &&
- a->is_all_day == b->is_all_day;
-}
-
-static void
-calendar_appointment_copy (CalendarAppointment *appointment,
- CalendarAppointment *appointment_copy)
-{
- GSList *l;
-
- g_assert (appointment != NULL);
- g_assert (appointment_copy != NULL);
-
- appointment_copy->occurrences = g_slist_copy (appointment->occurrences);
- for (l = appointment_copy->occurrences; l; l = l->next)
- {
- CalendarOccurrence *occurrence = l->data;
- CalendarOccurrence *occurrence_copy;
-
- occurrence_copy = g_new0 (CalendarOccurrence, 1);
- occurrence_copy->start_time = occurrence->start_time;
- occurrence_copy->end_time = occurrence->end_time;
-
- l->data = occurrence_copy;
- }
-
- appointment_copy->uid = g_strdup (appointment->uid);
- appointment_copy->uri = g_strdup (appointment->uri);
- appointment_copy->summary = g_strdup (appointment->summary);
- appointment_copy->description = g_strdup (appointment->description);
- appointment_copy->color_string = g_strdup (appointment->color_string);
- appointment_copy->start_time = appointment->start_time;
- appointment_copy->end_time = appointment->end_time;
- appointment_copy->is_all_day = appointment->is_all_day;
-}
-
-static void
-calendar_appointment_finalize (CalendarAppointment *appointment)
-{
- GSList *l;
-
- for (l = appointment->occurrences; l; l = l->next)
- g_free (l->data);
- g_slist_free (appointment->occurrences);
- appointment->occurrences = NULL;
-
- g_free (appointment->uid);
- appointment->uid = NULL;
-
- g_free (appointment->rid);
- appointment->rid = NULL;
-
- g_free (appointment->uri);
- appointment->uri = NULL;
-
- g_free (appointment->summary);
- appointment->summary = NULL;
-
- g_free (appointment->description);
- appointment->description = NULL;
-
- g_free (appointment->color_string);
- appointment->color_string = NULL;
-
- appointment->start_time = 0;
- appointment->is_all_day = FALSE;
-}
-
-static void
-calendar_appointment_init (CalendarAppointment *appointment,
- icalcomponent *ical,
- CalendarClientSource *source,
- icaltimezone *default_zone)
-{
- appointment->uid = get_ical_uid (ical);
- appointment->rid = get_ical_rid (ical);
- appointment->uri = get_source_uri (source->source);
- appointment->summary = get_ical_summary (ical);
- appointment->description = get_ical_description (ical);
- appointment->color_string = get_source_color (source->source);
- appointment->start_time = get_ical_start_time (ical, default_zone);
- appointment->end_time = get_ical_end_time (ical, default_zone);
- appointment->is_all_day = get_ical_is_all_day (ical,
- appointment->start_time,
- default_zone);
-}
-
-static icaltimezone *
-resolve_timezone_id (const char *tzid,
- ECal *source)
-{
- icaltimezone *retval;
-
- retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
- if (!retval)
- {
- e_cal_get_timezone (source, tzid, &retval, NULL);
- }
-
- return retval;
-}
-
-static gboolean
-calendar_appointment_collect_occurrence (ECalComponent *component,
- time_t occurrence_start,
- time_t occurrence_end,
- gpointer data)
-{
- CalendarOccurrence *occurrence;
- GSList **collect_loc = data;
-
- occurrence = g_new0 (CalendarOccurrence, 1);
- occurrence->start_time = occurrence_start;
- occurrence->end_time = occurrence_end;
-
- *collect_loc = g_slist_prepend (*collect_loc, occurrence);
-
- return TRUE;
-}
-
-static void
-calendar_appointment_generate_ocurrences (CalendarAppointment *appointment,
- icalcomponent *ical,
- ECal *source,
- time_t start,
- time_t end,
- icaltimezone *default_zone)
-{
- ECalComponent *ecal;
-
- g_assert (appointment->occurrences == NULL);
-
- ecal = e_cal_component_new ();
- e_cal_component_set_icalcomponent (ecal,
- icalcomponent_new_clone (ical));
-
- e_cal_recur_generate_instances (ecal,
- start,
- end,
- calendar_appointment_collect_occurrence,
- &appointment->occurrences,
- (ECalRecurResolveTimezoneFn) resolve_timezone_id,
- source,
- default_zone);
-
- g_object_unref (ecal);
-
- appointment->occurrences = g_slist_reverse (appointment->occurrences);
-}
-
-static inline gboolean
-calendar_task_equal (CalendarTask *a,
- CalendarTask *b)
-{
- return
- null_safe_strcmp (a->uid, b->uid) == 0 &&
- null_safe_strcmp (a->summary, b->summary) == 0 &&
- null_safe_strcmp (a->description, b->description) == 0 &&
- null_safe_strcmp (a->color_string, b->color_string) == 0 &&
- a->start_time == b->start_time &&
- a->due_time == b->due_time &&
- a->percent_complete == b->percent_complete &&
- a->completed_time == b->completed_time &&
- a->priority == b->priority;
-}
-
-static void
-calendar_task_copy (CalendarTask *task,
- CalendarTask *task_copy)
-{
- g_assert (task != NULL);
- g_assert (task_copy != NULL);
-
- task_copy->uid = g_strdup (task->uid);
- task_copy->summary = g_strdup (task->summary);
- task_copy->description = g_strdup (task->description);
- task_copy->color_string = g_strdup (task->color_string);
- task_copy->start_time = task->start_time;
- task_copy->due_time = task->due_time;
- task_copy->percent_complete = task->percent_complete;
- task_copy->completed_time = task->completed_time;
- task_copy->priority = task->priority;
-}
-
-static void
-calendar_task_finalize (CalendarTask *task)
-{
- g_free (task->uid);
- task->uid = NULL;
-
- g_free (task->summary);
- task->summary = NULL;
-
- g_free (task->description);
- task->description = NULL;
-
- g_free (task->color_string);
- task->color_string = NULL;
-
- task->percent_complete = 0;
-}
-
-static void
-calendar_task_init (CalendarTask *task,
- icalcomponent *ical,
- CalendarClientSource *source,
- icaltimezone *default_zone)
-{
- task->uid = get_ical_uid (ical);
- task->summary = get_ical_summary (ical);
- task->description = get_ical_description (ical);
- task->color_string = get_source_color (source->source);
- task->start_time = get_ical_start_time (ical, default_zone);
- task->due_time = get_ical_due_time (ical, default_zone);
- task->percent_complete = get_ical_percent_complete (ical);
- task->completed_time = get_ical_completed_time (ical, default_zone);
- task->priority = get_ical_priority (ical);
-}
-
-void
-calendar_event_free (CalendarEvent *event)
-{
- switch (event->type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- calendar_appointment_finalize (CALENDAR_APPOINTMENT (event));
- break;
- case CALENDAR_EVENT_TASK:
- calendar_task_finalize (CALENDAR_TASK (event));
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- g_free (event);
-}
-
-static CalendarEvent *
-calendar_event_new (icalcomponent *ical,
- CalendarClientSource *source,
- icaltimezone *default_zone)
-{
- CalendarEvent *event;
-
- event = g_new0 (CalendarEvent, 1);
-
- switch (icalcomponent_isa (ical))
- {
- case ICAL_VEVENT_COMPONENT:
- event->type = CALENDAR_EVENT_APPOINTMENT;
- calendar_appointment_init (CALENDAR_APPOINTMENT (event),
- ical,
- source,
- default_zone);
- break;
- case ICAL_VTODO_COMPONENT:
- event->type = CALENDAR_EVENT_TASK;
- calendar_task_init (CALENDAR_TASK (event),
- ical,
- source,
- default_zone);
- break;
- default:
- g_warning ("Unknown calendar component type: %d\n",
- icalcomponent_isa (ical));
- g_free (event);
- return NULL;
- }
-
- return event;
-}
-
-static CalendarEvent *
-calendar_event_copy (CalendarEvent *event)
-{
- CalendarEvent *retval;
-
- if (!event)
- return NULL;
-
- retval = g_new0 (CalendarEvent, 1);
-
- retval->type = event->type;
-
- switch (event->type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- calendar_appointment_copy (CALENDAR_APPOINTMENT (event),
- CALENDAR_APPOINTMENT (retval));
- break;
- case CALENDAR_EVENT_TASK:
- calendar_task_copy (CALENDAR_TASK (event),
- CALENDAR_TASK (retval));
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- return retval;
-}
-
-static char *
-calendar_event_get_uid (CalendarEvent *event)
-{
- switch (event->type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- return g_strdup_printf ("%s%s", CALENDAR_APPOINTMENT (event)->uid, CALENDAR_APPOINTMENT (event)->rid ? CALENDAR_APPOINTMENT (event)->rid : "");
- break;
- case CALENDAR_EVENT_TASK:
- return g_strdup (CALENDAR_TASK (event)->uid);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- return NULL;
-}
-
-static gboolean
-calendar_event_equal (CalendarEvent *a,
- CalendarEvent *b)
-{
- if (!a && !b)
- return TRUE;
-
- if ((a && !b) || (!a && b))
- return FALSE;
-
- if (a->type != b->type)
- return FALSE;
-
- switch (a->type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- return calendar_appointment_equal (CALENDAR_APPOINTMENT (a),
- CALENDAR_APPOINTMENT (b));
- case CALENDAR_EVENT_TASK:
- return calendar_task_equal (CALENDAR_TASK (a),
- CALENDAR_TASK (b));
- default:
- break;
- }
-
- g_assert_not_reached ();
-
- return FALSE;
-}
-
-static void
-calendar_event_generate_ocurrences (CalendarEvent *event,
- icalcomponent *ical,
- ECal *source,
- time_t start,
- time_t end,
- icaltimezone *default_zone)
-{
- if (event->type != CALENDAR_EVENT_APPOINTMENT)
- return;
-
- calendar_appointment_generate_ocurrences (CALENDAR_APPOINTMENT (event),
- ical,
- source,
- start,
- end,
- default_zone);
-}
-
-static inline void
-calendar_event_debug_dump (CalendarEvent *event)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
- switch (event->type)
- {
- case CALENDAR_EVENT_APPOINTMENT:
- {
- char *start_str;
- char *end_str;
- GSList *l;
-
- start_str = CALENDAR_APPOINTMENT (event)->start_time ?
- isodate_from_time_t (CALENDAR_APPOINTMENT (event)->start_time) :
- g_strdup ("(undefined)");
- end_str = CALENDAR_APPOINTMENT (event)->end_time ?
- isodate_from_time_t (CALENDAR_APPOINTMENT (event)->end_time) :
- g_strdup ("(undefined)");
-
- dprintf ("Appointment: uid '%s', summary '%s', description '%s', "
- "start_time '%s', end_time '%s', is_all_day %s\n",
- CALENDAR_APPOINTMENT (event)->uid,
- CALENDAR_APPOINTMENT (event)->summary,
- CALENDAR_APPOINTMENT (event)->description,
- start_str,
- end_str,
- CALENDAR_APPOINTMENT (event)->is_all_day ? "(true)" : "(false)");
-
- g_free (start_str);
- g_free (end_str);
-
- dprintf (" Occurrences:\n");
- for (l = CALENDAR_APPOINTMENT (event)->occurrences; l; l = l->next)
- {
- CalendarOccurrence *occurrence = l->data;
-
- start_str = occurrence->start_time ?
- isodate_from_time_t (occurrence->start_time) :
- g_strdup ("(undefined)");
-
- end_str = occurrence->end_time ?
- isodate_from_time_t (occurrence->end_time) :
- g_strdup ("(undefined)");
-
- dprintf (" start_time '%s', end_time '%s'\n",
- start_str, end_str);
-
- g_free (start_str);
- g_free (end_str);
- }
- }
- break;
- case CALENDAR_EVENT_TASK:
- {
- char *start_str;
- char *due_str;
- char *completed_str;
-
- start_str = CALENDAR_TASK (event)->start_time ?
- isodate_from_time_t (CALENDAR_TASK (event)->start_time) :
- g_strdup ("(undefined)");
- due_str = CALENDAR_TASK (event)->due_time ?
- isodate_from_time_t (CALENDAR_TASK (event)->due_time) :
- g_strdup ("(undefined)");
- completed_str = CALENDAR_TASK (event)->completed_time ?
- isodate_from_time_t (CALENDAR_TASK (event)->completed_time) :
- g_strdup ("(undefined)");
-
- dprintf ("Task: uid '%s', summary '%s', description '%s', "
- "start_time '%s', due_time '%s', percent_complete %d, completed_time '%s'\n",
- CALENDAR_TASK (event)->uid,
- CALENDAR_TASK (event)->summary,
- CALENDAR_TASK (event)->description,
- start_str,
- due_str,
- CALENDAR_TASK (event)->percent_complete,
- completed_str);
-
- g_free (completed_str);
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-#endif
-}
-
-static inline CalendarClientQuery *
-goddamn_this_is_crack (CalendarClientSource *source,
- ECalView *view,
- gboolean *emit_signal)
-{
- g_assert (view != NULL);
-
- if (source->completed_query.view == view)
- {
- if (emit_signal)
- *emit_signal = TRUE;
- return &source->completed_query;
- }
- else if (source->in_progress_query.view == view)
- {
- if (emit_signal)
- *emit_signal = FALSE;
- return &source->in_progress_query;
- }
-
- g_assert_not_reached ();
-
- return NULL;
-}
-
-static void
-calendar_client_handle_query_completed (CalendarClientSource *source,
- ECalendarStatus status,
- ECalView *view)
-{
- CalendarClientQuery *query;
-
- query = goddamn_this_is_crack (source, view, NULL);
-
- dprintf ("Query %p completed: %s\n", query, e_cal_get_error_message (status));
-
- if (status != E_CALENDAR_STATUS_OK)
- {
- g_warning ("Calendar query failed: %s\n",
- e_cal_get_error_message (status));
- calendar_client_stop_query (source->client, source, query);
- return;
- }
-
- g_assert (source->query_in_progress != FALSE);
- g_assert (query == &source->in_progress_query);
-
- calendar_client_query_finalize (&source->completed_query);
-
- source->completed_query = source->in_progress_query;
- source->query_completed = TRUE;
-
- source->query_in_progress = FALSE;
- source->in_progress_query.view = NULL;
- source->in_progress_query.events = NULL;
-
- g_signal_emit (source->client, source->changed_signal_id, 0);
-}
-
-static void
-calendar_client_handle_query_result (CalendarClientSource *source,
- GList *objects,
- ECalView *view)
-{
- CalendarClientQuery *query;
- CalendarClient *client;
- gboolean emit_signal;
- gboolean events_changed;
- GList *l;
- time_t month_begin;
- time_t month_end;
-
- client = source->client;
-
- query = goddamn_this_is_crack (source, view, &emit_signal);
-
- dprintf ("Query %p result: %d objects:\n",
- query, g_list_length (objects));
-
- month_begin = make_time_for_day_begin (1,
- client->priv->month,
- client->priv->year);
-
- month_end = make_time_for_day_begin (1,
- client->priv->month + 1,
- client->priv->year);
-
- events_changed = FALSE;
- for (l = objects; l; l = l->next)
- {
- CalendarEvent *event;
- CalendarEvent *old_event;
- icalcomponent *ical = l->data;
- char *uid;
-
- event = calendar_event_new (ical, source, client->priv->zone);
- if (!event)
- continue;
-
- calendar_event_generate_ocurrences (event,
- ical,
- source->source,
- month_begin,
- month_end,
- client->priv->zone);
-
- uid = calendar_event_get_uid (event);
-
- old_event = g_hash_table_lookup (query->events, uid);
-
- if (!calendar_event_equal (event, old_event))
- {
- dprintf ("Event %s: ", old_event ? "modified" : "added");
-
- calendar_event_debug_dump (event);
-
- g_hash_table_replace (query->events, uid, event);
-
- events_changed = TRUE;
- }
- else
- {
- g_free (uid);
- }
- }
-
- if (emit_signal && events_changed)
- {
- g_signal_emit (source->client, source->changed_signal_id, 0);
- }
-}
-
-static gboolean
-check_object_remove (gpointer key,
- gpointer value,
- gpointer data)
-{
- char *uid = data;
- ssize_t len;
-
- len = strlen (uid);
-
- if (len <= strlen (key) && strncmp (uid, key, len) == 0)
- {
- dprintf ("Event removed: ");
-
- calendar_event_debug_dump (value);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-calendar_client_handle_objects_removed (CalendarClientSource *source,
- GList *ids,
- ECalView *view)
-{
- CalendarClientQuery *query;
- gboolean emit_signal;
- gboolean events_changed;
- GList *l;
-
- query = goddamn_this_is_crack (source, view, &emit_signal);
-
- events_changed = FALSE;
- for (l = ids; l; l = l->next)
- {
- CalendarEvent *event;
- ECalComponentId *id = l->data;
- char *uid = g_strdup_printf ("%s%s", id->uid, id->rid ? id->rid : "");
-
- if (!id->rid || !(*id->rid))
- {
- int size = g_hash_table_size (query->events);
-
- g_hash_table_foreach_remove (query->events, check_object_remove, id->uid);
-
- if (size != g_hash_table_size (query->events))
- events_changed = TRUE;
- }
- else if ((event = g_hash_table_lookup (query->events, uid)))
- {
- dprintf ("Event removed: ");
-
- calendar_event_debug_dump (event);
-
- g_assert (g_hash_table_remove (query->events, uid));
-
- events_changed = TRUE;
- }
- g_free (uid);
- }
-
- if (emit_signal && events_changed)
- {
- g_signal_emit (source->client, source->changed_signal_id, 0);
- }
-}
-
-static void
-calendar_client_query_finalize (CalendarClientQuery *query)
-{
- if (query->view)
- g_object_unref (query->view);
- query->view = NULL;
-
- if (query->events)
- g_hash_table_destroy (query->events);
- query->events = NULL;
-}
-
-static void
-calendar_client_stop_query (CalendarClient *client,
- CalendarClientSource *source,
- CalendarClientQuery *query)
-{
- if (query == &source->in_progress_query)
- {
- dprintf ("Stopping in progress query %p\n", query);
-
- g_assert (source->query_in_progress != FALSE);
-
- source->query_in_progress = FALSE;
- }
- else if (query == &source->completed_query)
- {
- dprintf ("Stopping completed query %p\n", query);
-
- g_assert (source->query_completed != FALSE);
-
- source->query_completed = FALSE;
- }
- else
- g_assert_not_reached ();
-
- calendar_client_query_finalize (query);
-}
-
-static void
-calendar_client_start_query (CalendarClient *client,
- CalendarClientSource *source,
- const char *query)
-{
- ECalView *view = NULL;
- GError *error = NULL;
-
- if (!e_cal_get_query (source->source, query, &view, &error))
- {
- g_warning ("Error preparing the query: '%s': %s\n",
- query, error->message);
- g_error_free (error);
- return;
- }
-
- g_assert (view != NULL);
-
- if (source->query_in_progress)
- calendar_client_stop_query (client, source, &source->in_progress_query);
-
- dprintf ("Starting query %p: '%s'\n", &source->in_progress_query, query);
-
- source->query_in_progress = TRUE;
- source->in_progress_query.view = view;
- source->in_progress_query.events =
- g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) calendar_event_free);
-
- g_signal_connect_swapped (view, "objects-added",
- G_CALLBACK (calendar_client_handle_query_result),
- source);
- g_signal_connect_swapped (view, "objects-modified",
- G_CALLBACK (calendar_client_handle_query_result),
- source);
- g_signal_connect_swapped (view, "objects-removed",
- G_CALLBACK (calendar_client_handle_objects_removed),
- source);
- g_signal_connect_swapped (view, "view-done",
- G_CALLBACK (calendar_client_handle_query_completed),
- source);
-
- e_cal_view_start (view);
-}
-
-static void
-calendar_client_update_appointments (CalendarClient *client)
-{
- GSList *l;
- char *query;
- char *month_begin;
- char *month_end;
-
- if (client->priv->month == -1 ||
- client->priv->year == -1)
- return;
-
- month_begin = make_isodate_for_day_begin (1,
- client->priv->month,
- client->priv->year);
-
- month_end = make_isodate_for_day_begin (1,
- client->priv->month + 1,
- client->priv->year);
-
- query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
- "(make-time \"%s\")",
- month_begin, month_end);
-
- for (l = client->priv->appointment_sources; l; l = l->next)
- {
- CalendarClientSource *cs = l->data;
-
- if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED)
- continue;
-
- calendar_client_start_query (client, cs, query);
- }
-
- g_free (month_begin);
- g_free (month_end);
- g_free (query);
-}
-
-/* FIXME:
- * perhaps we should use evo's "hide_completed_tasks" pref?
- */
-static void
-calendar_client_update_tasks (CalendarClient *client)
-{
- GSList *l;
- char *query;
-
-#ifdef FIX_BROKEN_TASKS_QUERY
- /* FIXME: this doesn't work for tasks without a start or
- * due date
- * Look at filter_task() to see the behaviour we
- * want.
- */
-
- char *day_begin;
- char *day_end;
-
- if (client->priv->day == -1 ||
- client->priv->month == -1 ||
- client->priv->year == -1)
- return;
-
- day_begin = make_isodate_for_day_begin (client->priv->day,
- client->priv->month,
- client->priv->year);
-
- day_end = make_isodate_for_day_begin (client->priv->day + 1,
- client->priv->month,
- client->priv->year);
- if (!day_begin || !day_end)
- {
- g_warning ("Cannot run query with invalid date: %dd %dy %dm\n",
- client->priv->day,
- client->priv->month,
- client->priv->year);
- g_free (day_begin);
- g_free (day_end);
- return;
- }
-
- query = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") "
- "(make-time \"%s\")) "
- "(or (not is-completed?) "
- "(and (is-completed?) "
- "(not (completed-before? (make-time \"%s\"))))))",
- day_begin, day_end, day_begin);
-#else
- query = g_strdup ("#t");
-#endif /* FIX_BROKEN_TASKS_QUERY */
-
- for (l = client->priv->task_sources; l; l = l->next)
- {
- CalendarClientSource *cs = l->data;
-
- if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED)
- continue;
-
- calendar_client_start_query (client, cs, query);
- }
-
-#ifdef FIX_BROKEN_TASKS_QUERY
- g_free (day_begin);
- g_free (day_end);
-#endif
- g_free (query);
-}
-
-static void
-calendar_client_source_finalize (CalendarClientSource *source)
-{
- source->client = NULL;
-
- if (source->source) {
- g_signal_handlers_disconnect_by_func (source->source,
- cal_opened_cb, source);
- g_object_unref (source->source);
- }
- source->source = NULL;
-
- calendar_client_query_finalize (&source->completed_query);
- calendar_client_query_finalize (&source->in_progress_query);
-
- source->query_completed = FALSE;
- source->query_in_progress = FALSE;
-}
-
-static int
-compare_calendar_sources (CalendarClientSource *s1,
- CalendarClientSource *s2)
-{
- return (s1->source == s2->source) ? 0 : 1;
-}
-
-static GSList *
-calendar_client_update_sources_list (CalendarClient *client,
- GSList *sources,
- GSList *esources,
- guint changed_signal_id)
-{
- GSList *retval, *l;
-
- retval = NULL;
-
- for (l = esources; l; l = l->next)
- {
- CalendarClientSource dummy_source;
- CalendarClientSource *new_source;
- GSList *s;
- ECal *esource = l->data;
-
- dummy_source.source = esource;
-
- dprintf ("update_sources_list: adding client %s: ",
- e_source_peek_uid (e_cal_get_source (esource)));
-
- if ((s = g_slist_find_custom (sources,
- &dummy_source,
- (GCompareFunc) compare_calendar_sources)))
- {
- dprintf ("already on list\n");
- new_source = s->data;
- sources = g_slist_delete_link (sources, s);
- }
- else
- {
- dprintf ("added\n");
- new_source = g_new0 (CalendarClientSource, 1);
- new_source->client = client;
- new_source->source = g_object_ref (esource);
- new_source->changed_signal_id = changed_signal_id;
- }
-
- retval = g_slist_prepend (retval, new_source);
- }
-
- for (l = sources; l; l = l->next)
- {
- CalendarClientSource *source = l->data;
-
- dprintf ("Removing client %s from list\n",
- e_source_peek_uid (e_cal_get_source (source->source)));
-
- calendar_client_source_finalize (source);
- g_free (source);
- }
- g_slist_free (sources);
-
- return retval;
-}
-
-static void
-calendar_client_appointment_sources_changed (CalendarClient *client)
-{
- GSList *esources;
-
- dprintf ("appointment_sources_changed: updating ...\n");
-
- esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
-
- client->priv->appointment_sources =
- calendar_client_update_sources_list (client,
- client->priv->appointment_sources,
- esources,
- signals [APPOINTMENTS_CHANGED]);
-
- load_calendars (client, CALENDAR_EVENT_APPOINTMENT);
- calendar_client_update_appointments (client);
-}
-
-static void
-calendar_client_task_sources_changed (CalendarClient *client)
-{
- GSList *esources;
-
- dprintf ("task_sources_changed: updating ...\n");
-
- esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
-
- client->priv->task_sources =
- calendar_client_update_sources_list (client,
- client->priv->task_sources,
- esources,
- signals [TASKS_CHANGED]);
-
- load_calendars (client, CALENDAR_EVENT_TASK);
- calendar_client_update_tasks (client);
-}
-
-void
-calendar_client_get_date (CalendarClient *client,
- guint *year,
- guint *month,
- guint *day)
-{
- g_return_if_fail (CALENDAR_IS_CLIENT (client));
-
- if (year)
- *year = client->priv->year;
-
- if (month)
- *month = client->priv->month;
-
- if (day)
- *day = client->priv->day;
-}
-
-void
-calendar_client_select_month (CalendarClient *client,
- guint month,
- guint year)
-{
- g_return_if_fail (CALENDAR_IS_CLIENT (client));
- g_return_if_fail (month <= 11);
-
- if (client->priv->year != year || client->priv->month != month)
- {
- client->priv->month = month;
- client->priv->year = year;
-
- calendar_client_update_appointments (client);
- calendar_client_update_tasks (client);
-
- g_object_freeze_notify (G_OBJECT (client));
- g_object_notify (G_OBJECT (client), "month");
- g_object_notify (G_OBJECT (client), "year");
- g_object_thaw_notify (G_OBJECT (client));
- }
-}
-
-void
-calendar_client_select_day (CalendarClient *client,
- guint day)
-{
- g_return_if_fail (CALENDAR_IS_CLIENT (client));
- g_return_if_fail (day <= 31);
-
- if (client->priv->day != day)
- {
- client->priv->day = day;
-
- /* don't need to update appointments unless
- * the selected month changes
- */
-#ifdef FIX_BROKEN_TASKS_QUERY
- calendar_client_update_tasks (client);
-#endif
-
- g_object_notify (G_OBJECT (client), "day");
- }
-}
-
-typedef struct
-{
- CalendarClient *client;
- GSList *events;
- time_t start_time;
- time_t end_time;
-} FilterData;
-
-typedef void (* CalendarEventFilterFunc) (const char *uid,
- CalendarEvent *event,
- FilterData *filter_data);
-
-static void
-filter_appointment (const char *uid,
- CalendarEvent *event,
- FilterData *filter_data)
-{
- GSList *occurrences, *l;
-
- if (event->type != CALENDAR_EVENT_APPOINTMENT)
- return;
-
- occurrences = CALENDAR_APPOINTMENT (event)->occurrences;
- CALENDAR_APPOINTMENT (event)->occurrences = NULL;
-
- for (l = occurrences; l; l = l->next)
- {
- CalendarOccurrence *occurrence = l->data;
- time_t start_time = occurrence->start_time;
- time_t end_time = occurrence->end_time;
-
- if ((start_time >= filter_data->start_time &&
- start_time < filter_data->end_time) ||
- (start_time <= filter_data->start_time &&
- (end_time - 1) > filter_data->start_time))
- {
- CalendarEvent *new_event;
-
- new_event = calendar_event_copy (event);
-
- CALENDAR_APPOINTMENT (new_event)->start_time = occurrence->start_time;
- CALENDAR_APPOINTMENT (new_event)->end_time = occurrence->end_time;
-
- filter_data->events = g_slist_prepend (filter_data->events, new_event);
- }
- }
-
- CALENDAR_APPOINTMENT (event)->occurrences = occurrences;
-}
-
-static void
-filter_task (const char *uid,
- CalendarEvent *event,
- FilterData *filter_data)
-{
-#ifdef FIX_BROKEN_TASKS_QUERY
- CalendarTask *task;
-#endif
-
- if (event->type != CALENDAR_EVENT_TASK)
- return;
-
-#ifdef FIX_BROKEN_TASKS_QUERY
- task = CALENDAR_TASK (event);
-
- if (task->start_time && task->start_time > filter_data->start_time)
- return;
-
- if (task->completed_time &&
- (task->completed_time < filter_data->start_time ||
- task->completed_time > filter_data->end_time))
- return;
-#endif /* FIX_BROKEN_TASKS_QUERY */
-
- filter_data->events = g_slist_prepend (filter_data->events,
- calendar_event_copy (event));
-}
-
-static GSList *
-calendar_client_filter_events (CalendarClient *client,
- GSList *sources,
- CalendarEventFilterFunc filter_func,
- time_t start_time,
- time_t end_time)
-{
- FilterData filter_data;
- GSList *l;
- GSList *retval;
-
- if (!sources)
- return NULL;
-
- filter_data.client = client;
- filter_data.events = NULL;
- filter_data.start_time = start_time;
- filter_data.end_time = end_time;
-
- retval = NULL;
- for (l = sources; l; l = l->next)
- {
- CalendarClientSource *source = l->data;
-
- if (source->query_completed)
- {
- filter_data.events = NULL;
- g_hash_table_foreach (source->completed_query.events,
- (GHFunc) filter_func,
- &filter_data);
-
- filter_data.events = g_slist_reverse (filter_data.events);
-
- retval = g_slist_concat (retval, filter_data.events);
- }
- }
-
- return retval;
-}
-
-GSList *
-calendar_client_get_events (CalendarClient *client,
- CalendarEventType event_mask)
-{
- GSList *appointments;
- GSList *tasks;
- time_t day_begin;
- time_t day_end;
-
- g_return_val_if_fail (CALENDAR_IS_CLIENT (client), NULL);
- g_return_val_if_fail (client->priv->day != -1 &&
- client->priv->month != -1 &&
- client->priv->year != -1, NULL);
-
- day_begin = make_time_for_day_begin (client->priv->day,
- client->priv->month,
- client->priv->year);
- day_end = make_time_for_day_begin (client->priv->day + 1,
- client->priv->month,
- client->priv->year);
-
- appointments = NULL;
- if (event_mask & CALENDAR_EVENT_APPOINTMENT)
- {
- appointments = calendar_client_filter_events (client,
- client->priv->appointment_sources,
- filter_appointment,
- day_begin,
- day_end);
- }
-
- tasks = NULL;
- if (event_mask & CALENDAR_EVENT_TASK)
- {
- tasks = calendar_client_filter_events (client,
- client->priv->task_sources,
- filter_task,
- day_begin,
- day_end);
- }
-
- return g_slist_concat (appointments, tasks);
-}
-
-static inline int
-day_from_time_t (time_t t)
-{
- struct tm *tm = localtime (&t);
-
- g_assert (tm == NULL || (tm->tm_mday >=1 && tm->tm_mday <= 31));
-
- return tm ? tm->tm_mday : 0;
-}
-
-void
-calendar_client_foreach_appointment_day (CalendarClient *client,
- CalendarDayIter iter_func,
- gpointer user_data)
-{
- GSList *appointments, *l;
- gboolean marked_days [32] = { FALSE, };
- time_t month_begin;
- time_t month_end;
- int i;
-
- g_return_if_fail (CALENDAR_IS_CLIENT (client));
- g_return_if_fail (iter_func != NULL);
- g_return_if_fail (client->priv->month != -1 &&
- client->priv->year != -1);
-
- month_begin = make_time_for_day_begin (1,
- client->priv->month,
- client->priv->year);
- month_end = make_time_for_day_begin (1,
- client->priv->month + 1,
- client->priv->year);
-
- appointments = calendar_client_filter_events (client,
- client->priv->appointment_sources,
- filter_appointment,
- month_begin,
- month_end);
- for (l = appointments; l; l = l->next)
- {
- CalendarAppointment *appointment = l->data;
-
- if (appointment->start_time)
- {
- time_t day_time = appointment->start_time;
-
- if (day_time >= month_begin)
- marked_days [day_from_time_t (day_time)] = TRUE;
-
- if (appointment->end_time)
- {
- int day_offset;
- int duration = appointment->end_time - appointment->start_time;
- /* mark the days for the appointment, no need to add an extra one when duration is a multiple of 86400 */
- for (day_offset = 1; day_offset <= duration / 86400 && duration != day_offset * 86400; day_offset++)
- {
- time_t day_tm = appointment->start_time + day_offset * 86400;
-
- if (day_tm > month_end)
- break;
- if (day_tm >= month_begin)
- marked_days [day_from_time_t (day_tm)] = TRUE;
- }
- }
- }
- calendar_event_free (CALENDAR_EVENT (appointment));
- }
-
- g_slist_free (appointments);
-
- for (i = 1; i < 32; i++)
- {
- if (marked_days [i])
- iter_func (client, i, user_data);
- }
-}
-
-void
-calendar_client_set_task_completed (CalendarClient *client,
- char *task_uid,
- gboolean task_completed,
- guint percent_complete)
-{
- GSList *l;
- ECal *esource;
- icalcomponent *ical;
- icalproperty *prop;
- icalproperty_status status;
-
- g_return_if_fail (CALENDAR_IS_CLIENT (client));
- g_return_if_fail (task_uid != NULL);
- g_return_if_fail (task_completed == FALSE || percent_complete == 100);
-
- ical = NULL;
- esource = NULL;
- for (l = client->priv->task_sources; l; l = l->next)
- {
- CalendarClientSource *source = l->data;
-
- esource = source->source;
- e_cal_get_object (esource, task_uid, NULL, &ical, NULL);
- if (ical)
- break;
- }
-
- if (!ical)
- {
- g_warning ("Cannot locate task with uid = '%s'\n", task_uid);
- return;
- }
-
- g_assert (esource != NULL);
-
- /* Completed time */
- prop = icalcomponent_get_first_property (ical,
- ICAL_COMPLETED_PROPERTY);
- if (task_completed)
- {
- struct icaltimetype completed_time;
-
- completed_time = icaltime_current_time_with_zone (client->priv->zone);
- if (!prop)
- {
- icalcomponent_add_property (ical,
- icalproperty_new_completed (completed_time));
- }
- else
- {
- icalproperty_set_completed (prop, completed_time);
- }
- }
- else if (prop)
- {
- icalcomponent_remove_property (ical, prop);
- }
-
- /* Percent complete */
- prop = icalcomponent_get_first_property (ical,
- ICAL_PERCENTCOMPLETE_PROPERTY);
- if (!prop)
- {
- icalcomponent_add_property (ical,
- icalproperty_new_percentcomplete (percent_complete));
- }
- else
- {
- icalproperty_set_percentcomplete (prop, percent_complete);
- }
-
- /* Status */
- status = task_completed ? ICAL_STATUS_COMPLETED : ICAL_STATUS_NEEDSACTION;
- prop = icalcomponent_get_first_property (ical, ICAL_STATUS_PROPERTY);
- if (prop)
- {
- icalproperty_set_status (prop, status);
- }
- else
- {
- icalcomponent_add_property (ical,
- icalproperty_new_status (status));
- }
-
- e_cal_modify_object (esource, ical, CALOBJ_MOD_ALL, NULL);
-}
+++ /dev/null
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- * Mark McLoughlin <mark@skynet.ie>
- * William Jon McCann <mccann@jhu.edu>
- * Martin Grimme <martin@pycage.de>
- * Christian Kellner <gicmo@xatom.net>
- */
-
-#ifndef __CALENDAR_CLIENT_H__
-#define __CALENDAR_CLIENT_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-typedef enum
-{
- CALENDAR_EVENT_APPOINTMENT = 1 << 0,
- CALENDAR_EVENT_TASK = 1 << 1,
- CALENDAR_EVENT_ALL = (1 << 2) - 1
-} CalendarEventType;
-
-#define CALENDAR_TYPE_CLIENT (calendar_client_get_type ())
-#define CALENDAR_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_CLIENT, CalendarClient))
-#define CALENDAR_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_CLIENT, CalendarClientClass))
-#define CALENDAR_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_CLIENT))
-#define CALENDAR_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_CLIENT))
-#define CALENDAR_CLIENT_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_CLIENT, CalendarClientClass))
-
-typedef struct _CalendarClient CalendarClient;
-typedef struct _CalendarClientClass CalendarClientClass;
-typedef struct _CalendarClientPrivate CalendarClientPrivate;
-
-struct _CalendarClient
-{
- GObject parent;
- CalendarClientPrivate *priv;
-};
-
-struct _CalendarClientClass
-{
- GObjectClass parent_class;
-
- void (* appointments_changed) (CalendarClient *client);
- void (* tasks_changed) (CalendarClient *client);
-};
-
-
-typedef struct
-{
- time_t start_time;
- time_t end_time;
-} CalendarOccurrence;
-
-typedef struct
-{
- char *uid;
- char *rid;
- char *uri;
- char *summary;
- char *description;
- char *color_string;
- time_t start_time;
- time_t end_time;
- guint is_all_day : 1;
-
- /* Only used internally */
- GSList *occurrences;
-} CalendarAppointment;
-
-typedef struct
-{
- char *uid;
- char *summary;
- char *description;
- char *color_string;
- char *url;
- time_t start_time;
- time_t due_time;
- guint percent_complete;
- time_t completed_time;
- int priority;
-} CalendarTask;
-
-typedef struct
-{
- union
- {
- CalendarAppointment appointment;
- CalendarTask task;
- } event;
- CalendarEventType type;
-} CalendarEvent;
-
-#define CALENDAR_EVENT(e) ((CalendarEvent *)(e))
-#define CALENDAR_APPOINTMENT(e) ((CalendarAppointment *)(e))
-#define CALENDAR_TASK(e) ((CalendarTask *)(e))
-
-typedef void (* CalendarDayIter) (CalendarClient *client,
- guint day,
- gpointer user_data);
-
-
-GType calendar_client_get_type (void) G_GNUC_CONST;
-CalendarClient *calendar_client_new (void);
-
-void calendar_client_get_date (CalendarClient *client,
- guint *year,
- guint *month,
- guint *day);
-void calendar_client_select_month (CalendarClient *client,
- guint month,
- guint year);
-void calendar_client_select_day (CalendarClient *client,
- guint day);
-
-GSList *calendar_client_get_events (CalendarClient *client,
- CalendarEventType event_mask);
-void calendar_client_foreach_appointment_day (CalendarClient *client,
- CalendarDayIter iter_func,
- gpointer user_data);
-
-void calendar_client_set_task_completed (CalendarClient *client,
- char *task_uid,
- gboolean task_completed,
- guint percent_complete);
-
-void calendar_event_free (CalendarEvent *event);
-
-G_END_DECLS
-
-#endif /* __CALENDAR_CLIENT_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- * Mark McLoughlin <mark@skynet.ie>
- */
-
-#ifndef __CALENDAR_DEBUG_H__
-#define __CALENDAR_DEBUG_H__
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-#ifdef CALENDAR_ENABLE_DEBUG
-
-#include <stdio.h>
-
-#ifdef G_HAVE_ISO_VARARGS
-# define dprintf(...) fprintf (stderr, __VA_ARGS__);
-#elif defined(G_HAVE_GNUC_VARARGS)
-# define dprintf(args...) fprintf (stderr, args);
-#endif
-
-#else /* if !defined (CALENDAR_DEBUG) */
-
-#ifdef G_HAVE_ISO_VARARGS
-# define dprintf(...)
-#elif defined(G_HAVE_GNUC_VARARGS)
-# define dprintf(args...)
-#endif
-
-#endif /* CALENDAR_ENABLE_DEBUG */
-
-G_END_DECLS
-
-#endif /* __CALENDAR_DEBUG_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- * Mark McLoughlin <mark@skynet.ie>
- * William Jon McCann <mccann@jhu.edu>
- * Martin Grimme <martin@pycage.de>
- * Christian Kellner <gicmo@xatom.net>
- */
-
-#include <config.h>
-
-#include "calendar-sources.h"
-
-#include <libintl.h>
-#include <string.h>
-#include <gconf/gconf-client.h>
-#define HANDLE_LIBICAL_MEMORY
-#include <libecal/e-cal.h>
-#include <libedataserver/e-source-list.h>
-#include <libedataserverui/e-passwords.h>
-
-#undef CALENDAR_ENABLE_DEBUG
-#include "calendar-debug.h"
-
-#ifndef _
-#define _(x) gettext(x)
-#endif
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
-
-#define CALENDAR_SOURCES_EVO_DIR "/apps/evolution"
-#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
-#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display"
-#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars"
-#define CALENDAR_SOURCES_TASK_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
-#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/tasks"
-#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks"
-
-typedef struct _CalendarSourceData CalendarSourceData;
-
-struct _CalendarSourceData
-{
- ECalSourceType source_type;
- CalendarSources *sources;
- guint changed_signal;
-
- GSList *clients;
- GSList *selected_sources;
- ESourceList *esource_list;
-
- guint selected_sources_listener;
- char *selected_sources_dir;
-
- guint timeout_id;
-
- guint loaded : 1;
-};
-
-struct _CalendarSourcesPrivate
-{
- CalendarSourceData appointment_sources;
- CalendarSourceData task_sources;
-
- GConfClient *gconf_client;
-};
-
-static void calendar_sources_class_init (CalendarSourcesClass *klass);
-static void calendar_sources_init (CalendarSources *sources);
-static void calendar_sources_finalize (GObject *object);
-
-static void backend_died_cb (ECal *client, CalendarSourceData *source_data);
-static void calendar_sources_esource_list_changed (ESourceList *source_list,
- CalendarSourceData *source_data);
-
-enum
-{
- APPOINTMENT_SOURCES_CHANGED,
- TASK_SOURCES_CHANGED,
- LAST_SIGNAL
-};
-static guint signals [LAST_SIGNAL] = { 0, };
-
-static GObjectClass *parent_class = NULL;
-static CalendarSources *calendar_sources_singleton = NULL;
-
-GType
-calendar_sources_get_type (void)
-{
- static GType sources_type = 0;
-
- if (!sources_type)
- {
- static const GTypeInfo sources_info =
- {
- sizeof (CalendarSourcesClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) calendar_sources_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (CalendarSources),
- 0, /* n_preallocs */
- (GInstanceInitFunc) calendar_sources_init,
- };
-
- sources_type = g_type_register_static (G_TYPE_OBJECT,
- "CalendarSources",
- &sources_info, 0);
- }
-
- return sources_type;
-}
-
-static void
-calendar_sources_class_init (CalendarSourcesClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = calendar_sources_finalize;
-
- g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate));
-
- signals [APPOINTMENT_SOURCES_CHANGED] =
- g_signal_new ("appointment-sources-changed",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CalendarSourcesClass,
- appointment_sources_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- signals [TASK_SOURCES_CHANGED] =
- g_signal_new ("task-sources-changed",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (CalendarSourcesClass,
- task_sources_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-}
-
-static void
-calendar_sources_init (CalendarSources *sources)
-{
- sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
-
- sources->priv->appointment_sources.source_type = E_CAL_SOURCE_TYPE_EVENT;
- sources->priv->appointment_sources.sources = sources;
- sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
- sources->priv->appointment_sources.timeout_id = 0;
-
- sources->priv->task_sources.source_type = E_CAL_SOURCE_TYPE_TODO;
- sources->priv->task_sources.sources = sources;
- sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
- sources->priv->task_sources.timeout_id = 0;
-
- sources->priv->gconf_client = gconf_client_get_default ();
-}
-
-static void
-calendar_sources_finalize_source_data (CalendarSources *sources,
- CalendarSourceData *source_data)
-{
- if (source_data->loaded)
- {
- GSList *l;
-
- if (source_data->selected_sources_dir)
- {
- gconf_client_remove_dir (sources->priv->gconf_client,
- source_data->selected_sources_dir,
- NULL);
-
- g_free (source_data->selected_sources_dir);
- source_data->selected_sources_dir = NULL;
- }
-
- if (source_data->selected_sources_listener)
- {
- gconf_client_notify_remove (sources->priv->gconf_client,
- source_data->selected_sources_listener);
- source_data->selected_sources_listener = 0;
- }
-
- for (l = source_data->clients; l; l = l->next)
- {
- g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
- G_CALLBACK (backend_died_cb),
- source_data);
- g_object_unref (l->data);
- }
- g_slist_free (source_data->clients);
- source_data->clients = NULL;
-
- if (source_data->esource_list)
- {
- g_signal_handlers_disconnect_by_func (source_data->esource_list,
- G_CALLBACK (calendar_sources_esource_list_changed),
- source_data);
- g_object_unref (source_data->esource_list);
- }
- source_data->esource_list = NULL;
-
- for (l = source_data->selected_sources; l; l = l->next)
- g_free (l->data);
- g_slist_free (source_data->selected_sources);
- source_data->selected_sources = NULL;
-
- if (source_data->timeout_id != 0)
- {
- g_source_remove (source_data->timeout_id);
- source_data->timeout_id = 0;
- }
-
- source_data->loaded = FALSE;
- }
-}
-
-static void
-calendar_sources_finalize (GObject *object)
-{
- CalendarSources *sources = CALENDAR_SOURCES (object);
-
- calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
- calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
-
- if (sources->priv->gconf_client)
- g_object_unref (sources->priv->gconf_client);
- sources->priv->gconf_client = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-CalendarSources *
-calendar_sources_get (void)
-{
- gpointer singleton_location = &calendar_sources_singleton;
-
- if (calendar_sources_singleton)
- return g_object_ref (calendar_sources_singleton);
-
- calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL);
- g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton),
- singleton_location);
-
- return calendar_sources_singleton;
-}
-
-static gboolean
-is_source_selected (ESource *esource,
- GSList *selected_sources)
-{
- const char *uid;
- GSList *l;
-
- uid = e_source_peek_uid (esource);
-
- for (l = selected_sources; l; l = l->next)
- {
- const char *source = l->data;
-
- if (!strcmp (source, uid))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static char *
-auth_func_cb (ECal *ecal,
- const char *prompt,
- const char *key,
- gpointer user_data)
-{
- ESource *source;
- const gchar *auth_domain;
- const gchar *component_name;
-
- source = e_cal_get_source (ecal);
- auth_domain = e_source_get_property (source, "auth-domain");
- component_name = auth_domain ? auth_domain : "Calendar";
-
- return e_passwords_get_password (component_name, key);
-}
-
-/* The clients are just created here but not loaded */
-static ECal *
-get_ecal_from_source (ESource *esource,
- ECalSourceType source_type,
- GSList *existing_clients)
-{
- ECal *retval;
-
- if (existing_clients)
- {
- GSList *l;
-
- for (l = existing_clients; l; l = l->next)
- {
- ECal *client = E_CAL (l->data);
-
- if (e_source_equal (esource, e_cal_get_source (client)))
- {
- dprintf (" load_esource: found existing source ... returning that\n");
-
- return g_object_ref (client);
- }
- }
- }
-
- retval = e_cal_new (esource, source_type);
- if (!retval)
- {
- g_warning ("Could not load source '%s' from '%s'\n",
- e_source_peek_name (esource),
- e_source_peek_relative_uri (esource));
- return NULL;
- }
-
- e_cal_set_auth_func (retval, auth_func_cb, NULL);
-
- return retval;
-}
-
-/* - Order doesn't matter
- * - Can just compare object pointers since we
- * re-use client connections
- */
-static gboolean
-compare_ecal_lists (GSList *a,
- GSList *b)
-{
- GSList *l;
-
- if (g_slist_length (a) != g_slist_length (b))
- return FALSE;
-
- for (l = a; l; l = l->next)
- {
- if (!g_slist_find (b, l->data))
- return FALSE;
- }
-
- return TRUE;
-}
-
-static inline void
-debug_dump_selected_sources (GSList *selected_sources)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
- GSList *l;
-
- dprintf ("Selected sources:\n");
- for (l = selected_sources; l; l = l->next)
- {
- char *source = l->data;
-
- dprintf (" %s\n", source);
- }
- dprintf ("\n");
-#endif
-}
-
-static inline void
-debug_dump_ecal_list (GSList *ecal_list)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
- GSList *l;
-
- dprintf ("Loaded clients:\n");
- for (l = ecal_list; l; l = l->next)
- {
- ECal *client = l->data;
- ESource *source = e_cal_get_source (client);
-
- dprintf (" %s %s %s\n",
- e_source_peek_uid (source),
- e_source_peek_name (source),
- e_cal_get_uri (client));
- }
-#endif
-}
-
-static void
-calendar_sources_load_esource_list (CalendarSourceData *source_data);
-
-static gboolean
-backend_restart (gpointer data)
-{
- CalendarSourceData *source_data = data;
-
- calendar_sources_load_esource_list (source_data);
-
- source_data->timeout_id = 0;
-
- return FALSE;
-}
-
-static void
-backend_died_cb (ECal *client, CalendarSourceData *source_data)
-{
- const char *uristr;
-
- source_data->clients = g_slist_remove (source_data->clients, client);
- if (g_slist_length (source_data->clients) < 1)
- {
- g_slist_free (source_data->clients);
- source_data->clients = NULL;
- }
- uristr = e_cal_get_uri (client);
- g_warning ("The calendar backend for %s has crashed.", uristr);
-
- if (source_data->timeout_id != 0)
- {
- g_source_remove (source_data->timeout_id);
- source_data->timeout_id = 0;
- }
-
- source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
- source_data);
-}
-
-static void
-calendar_sources_load_esource_list (CalendarSourceData *source_data)
-{
- GSList *clients = NULL;
- GSList *groups, *l;
- gboolean emit_signal = FALSE;
-
- g_return_if_fail (source_data->esource_list != NULL);
-
- debug_dump_selected_sources (source_data->selected_sources);
-
- dprintf ("Source groups:\n");
- groups = e_source_list_peek_groups (source_data->esource_list);
- for (l = groups; l; l = l->next)
- {
- GSList *esources, *s;
-
- dprintf (" %s\n", e_source_group_peek_uid (l->data));
- dprintf (" sources:\n");
-
- esources = e_source_group_peek_sources (l->data);
- for (s = esources; s; s = s->next)
- {
- ESource *esource = E_SOURCE (s->data);
- ECal *client;
-
- dprintf (" type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
- source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task",
- e_source_peek_uid (esource),
- e_source_peek_name (esource),
- e_source_peek_relative_uri (esource));
-
- if (is_source_selected (esource, source_data->selected_sources) &&
- (client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
- {
- clients = g_slist_prepend (clients, client);
- }
- }
- }
- dprintf ("\n");
-
- if (source_data->loaded &&
- !compare_ecal_lists (source_data->clients, clients))
- emit_signal = TRUE;
-
- for (l = source_data->clients; l; l = l->next)
- {
- g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
- G_CALLBACK (backend_died_cb),
- source_data);
-
- g_object_unref (l->data);
- }
- g_slist_free (source_data->clients);
- source_data->clients = g_slist_reverse (clients);
-
- /* connect to backend_died after we disconnected the previous signal
- * handlers. If we do it before, we'll lose some handlers (for clients that
- * were already there before) */
- for (l = source_data->clients; l; l = l->next)
- {
- g_signal_connect (G_OBJECT (l->data), "backend_died",
- G_CALLBACK (backend_died_cb), source_data);
- }
-
- if (emit_signal)
- {
- dprintf ("Emitting %s-sources-changed signal\n",
- source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task");
- g_signal_emit (source_data->sources, source_data->changed_signal, 0);
- }
-
- debug_dump_ecal_list (source_data->clients);
-}
-
-static void
-calendar_sources_esource_list_changed (ESourceList *source_list,
- CalendarSourceData *source_data)
-
-{
- dprintf ("ESourceList changed, reloading\n");
-
- calendar_sources_load_esource_list (source_data);
-}
-
-static void
-calendar_sources_selected_sources_notify (GConfClient *client,
- guint cnx_id,
- GConfEntry *entry,
- CalendarSourceData *source_data)
-{
- GSList *l;
-
- if (!entry->value ||
- entry->value->type != GCONF_VALUE_LIST ||
- gconf_value_get_list_type (entry->value) != GCONF_VALUE_STRING)
- return;
-
- dprintf ("Selected sources key (%s) changed, reloading\n", entry->key);
-
- for (l = source_data->selected_sources; l; l = l->next)
- g_free (l->data);
- source_data->selected_sources = NULL;
-
- for (l = gconf_value_get_list (entry->value); l; l = l->next)
- {
- const char *source = gconf_value_get_string (l->data);
-
- source_data->selected_sources =
- g_slist_prepend (source_data->selected_sources,
- g_strdup (source));
- }
- source_data->selected_sources =
- g_slist_reverse (source_data->selected_sources);
-
- calendar_sources_load_esource_list (source_data);
-}
-
-static void
-calendar_sources_load_sources (CalendarSources *sources,
- CalendarSourceData *source_data,
- const char *sources_key,
- const char *selected_sources_key,
- const char *selected_sources_dir)
-{
- GConfClient *gconf_client;
- GError *error;
-
- dprintf ("---------------------------\n");
- dprintf ("Loading sources:\n");
- dprintf (" sources_key: %s\n", sources_key);
- dprintf (" selected_sources_key: %s\n", selected_sources_key);
- dprintf (" selected_sources_dir: %s\n", selected_sources_dir);
-
- gconf_client = sources->priv->gconf_client;
-
- error = NULL;
- source_data->selected_sources = gconf_client_get_list (gconf_client,
- selected_sources_key,
- GCONF_VALUE_STRING,
- &error);
- if (error)
- {
- g_warning ("Failed to get selected sources from '%s': %s\n",
- selected_sources_key,
- error->message);
- g_error_free (error);
- return;
- }
-
- gconf_client_add_dir (gconf_client,
- selected_sources_dir,
- GCONF_CLIENT_PRELOAD_NONE,
- NULL);
- source_data->selected_sources_dir = g_strdup (selected_sources_dir);
-
- source_data->selected_sources_listener =
- gconf_client_notify_add (gconf_client,
- selected_sources_dir,
- (GConfClientNotifyFunc) calendar_sources_selected_sources_notify,
- source_data, NULL, NULL);
-
- source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
- g_signal_connect (source_data->esource_list, "changed",
- G_CALLBACK (calendar_sources_esource_list_changed),
- source_data);
-
- calendar_sources_load_esource_list (source_data);
-
- source_data->loaded = TRUE;
-
- dprintf ("---------------------------\n");
-}
-
-GSList *
-calendar_sources_get_appointment_sources (CalendarSources *sources)
-{
- g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
-
- if (!sources->priv->appointment_sources.loaded)
- {
- calendar_sources_load_sources (sources,
- &sources->priv->appointment_sources,
- CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
- CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY,
- CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR);
- }
-
- return sources->priv->appointment_sources.clients;
-}
-
-GSList *
-calendar_sources_get_task_sources (CalendarSources *sources)
-{
- g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
-
- if (!sources->priv->task_sources.loaded)
- {
- calendar_sources_load_sources (sources,
- &sources->priv->task_sources,
- CALENDAR_SOURCES_TASK_SOURCES_KEY,
- CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY,
- CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR);
- }
-
- return sources->priv->task_sources.clients;
-}
+++ /dev/null
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- * Mark McLoughlin <mark@skynet.ie>
- * William Jon McCann <mccann@jhu.edu>
- * Martin Grimme <martin@pycage.de>
- * Christian Kellner <gicmo@xatom.net>
- */
-
-#ifndef __CALENDAR_SOURCES_H__
-#define __CALENDAR_SOURCES_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ())
-#define CALENDAR_SOURCES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources))
-#define CALENDAR_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
-#define CALENDAR_IS_SOURCES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES))
-#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES))
-#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
-
-typedef struct _CalendarSources CalendarSources;
-typedef struct _CalendarSourcesClass CalendarSourcesClass;
-typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
-
-struct _CalendarSources
-{
- GObject parent;
- CalendarSourcesPrivate *priv;
-};
-
-struct _CalendarSourcesClass
-{
- GObjectClass parent_class;
-
- void (* appointment_sources_changed) (CalendarSources *sources);
- void (* task_sources_changed) (CalendarSources *sources);
-};
-
-
-GType calendar_sources_get_type (void) G_GNUC_CONST;
-CalendarSources *calendar_sources_get (void);
-GSList *calendar_sources_get_appointment_sources (CalendarSources *sources);
-GSList *calendar_sources_get_task_sources (CalendarSources *sources);
-
-G_END_DECLS
-
-#endif /* __CALENDAR_SOURCES_H__ */
--- /dev/null
+Please keep in sync with gnome-panel.
--- /dev/null
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ * Mark McLoughlin <mark@skynet.ie>
+ */
+
+#ifndef __CALENDAR_DEBUG_H__
+#define __CALENDAR_DEBUG_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#ifdef CALENDAR_ENABLE_DEBUG
+
+#include <stdio.h>
+
+#ifdef G_HAVE_ISO_VARARGS
+# define dprintf(...) fprintf (stderr, __VA_ARGS__);
+#elif defined(G_HAVE_GNUC_VARARGS)
+# define dprintf(args...) fprintf (stderr, args);
+#endif
+
+#else /* if !defined (CALENDAR_DEBUG) */
+
+#ifdef G_HAVE_ISO_VARARGS
+# define dprintf(...)
+#elif defined(G_HAVE_GNUC_VARARGS)
+# define dprintf(args...)
+#endif
+
+#endif /* CALENDAR_ENABLE_DEBUG */
+
+G_END_DECLS
+
+#endif /* __CALENDAR_DEBUG_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ * Mark McLoughlin <mark@skynet.ie>
+ * William Jon McCann <mccann@jhu.edu>
+ * Martin Grimme <martin@pycage.de>
+ * Christian Kellner <gicmo@xatom.net>
+ */
+
+#include <config.h>
+
+#include "calendar-sources.h"
+
+#include <libintl.h>
+#include <string.h>
+#include <gconf/gconf-client.h>
+#define HANDLE_LIBICAL_MEMORY
+#include <libecal/e-cal.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserverui/e-passwords.h>
+
+#undef CALENDAR_ENABLE_DEBUG
+#include "calendar-debug.h"
+
+#ifndef _
+#define _(x) gettext(x)
+#endif
+
+#ifndef N_
+#define N_(x) x
+#endif
+
+#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
+
+#define CALENDAR_SOURCES_EVO_DIR "/apps/evolution"
+#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
+#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display"
+#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars"
+#define CALENDAR_SOURCES_TASK_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
+#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/tasks"
+#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks"
+
+typedef struct _CalendarSourceData CalendarSourceData;
+
+struct _CalendarSourceData
+{
+ ECalSourceType source_type;
+ CalendarSources *sources;
+ guint changed_signal;
+
+ GSList *clients;
+ GSList *selected_sources;
+ ESourceList *esource_list;
+
+ guint selected_sources_listener;
+ char *selected_sources_dir;
+
+ guint timeout_id;
+
+ guint loaded : 1;
+};
+
+struct _CalendarSourcesPrivate
+{
+ CalendarSourceData appointment_sources;
+ CalendarSourceData task_sources;
+
+ GConfClient *gconf_client;
+};
+
+static void calendar_sources_class_init (CalendarSourcesClass *klass);
+static void calendar_sources_init (CalendarSources *sources);
+static void calendar_sources_finalize (GObject *object);
+
+static void backend_died_cb (ECal *client, CalendarSourceData *source_data);
+static void calendar_sources_esource_list_changed (ESourceList *source_list,
+ CalendarSourceData *source_data);
+
+enum
+{
+ APPOINTMENT_SOURCES_CHANGED,
+ TASK_SOURCES_CHANGED,
+ LAST_SIGNAL
+};
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static GObjectClass *parent_class = NULL;
+static CalendarSources *calendar_sources_singleton = NULL;
+
+GType
+calendar_sources_get_type (void)
+{
+ static GType sources_type = 0;
+
+ if (!sources_type)
+ {
+ static const GTypeInfo sources_info =
+ {
+ sizeof (CalendarSourcesClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) calendar_sources_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (CalendarSources),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) calendar_sources_init,
+ };
+
+ sources_type = g_type_register_static (G_TYPE_OBJECT,
+ "CalendarSources",
+ &sources_info, 0);
+ }
+
+ return sources_type;
+}
+
+static void
+calendar_sources_class_init (CalendarSourcesClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = calendar_sources_finalize;
+
+ g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate));
+
+ signals [APPOINTMENT_SOURCES_CHANGED] =
+ g_signal_new ("appointment-sources-changed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CalendarSourcesClass,
+ appointment_sources_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals [TASK_SOURCES_CHANGED] =
+ g_signal_new ("task-sources-changed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CalendarSourcesClass,
+ task_sources_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+calendar_sources_init (CalendarSources *sources)
+{
+ sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
+
+ sources->priv->appointment_sources.source_type = E_CAL_SOURCE_TYPE_EVENT;
+ sources->priv->appointment_sources.sources = sources;
+ sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
+ sources->priv->appointment_sources.timeout_id = 0;
+
+ sources->priv->task_sources.source_type = E_CAL_SOURCE_TYPE_TODO;
+ sources->priv->task_sources.sources = sources;
+ sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
+ sources->priv->task_sources.timeout_id = 0;
+
+ sources->priv->gconf_client = gconf_client_get_default ();
+}
+
+static void
+calendar_sources_finalize_source_data (CalendarSources *sources,
+ CalendarSourceData *source_data)
+{
+ if (source_data->loaded)
+ {
+ GSList *l;
+
+ if (source_data->selected_sources_dir)
+ {
+ gconf_client_remove_dir (sources->priv->gconf_client,
+ source_data->selected_sources_dir,
+ NULL);
+
+ g_free (source_data->selected_sources_dir);
+ source_data->selected_sources_dir = NULL;
+ }
+
+ if (source_data->selected_sources_listener)
+ {
+ gconf_client_notify_remove (sources->priv->gconf_client,
+ source_data->selected_sources_listener);
+ source_data->selected_sources_listener = 0;
+ }
+
+ for (l = source_data->clients; l; l = l->next)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
+ G_CALLBACK (backend_died_cb),
+ source_data);
+ g_object_unref (l->data);
+ }
+ g_slist_free (source_data->clients);
+ source_data->clients = NULL;
+
+ if (source_data->esource_list)
+ {
+ g_signal_handlers_disconnect_by_func (source_data->esource_list,
+ G_CALLBACK (calendar_sources_esource_list_changed),
+ source_data);
+ g_object_unref (source_data->esource_list);
+ }
+ source_data->esource_list = NULL;
+
+ for (l = source_data->selected_sources; l; l = l->next)
+ g_free (l->data);
+ g_slist_free (source_data->selected_sources);
+ source_data->selected_sources = NULL;
+
+ if (source_data->timeout_id != 0)
+ {
+ g_source_remove (source_data->timeout_id);
+ source_data->timeout_id = 0;
+ }
+
+ source_data->loaded = FALSE;
+ }
+}
+
+static void
+calendar_sources_finalize (GObject *object)
+{
+ CalendarSources *sources = CALENDAR_SOURCES (object);
+
+ calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
+ calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
+
+ if (sources->priv->gconf_client)
+ g_object_unref (sources->priv->gconf_client);
+ sources->priv->gconf_client = NULL;
+
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+CalendarSources *
+calendar_sources_get (void)
+{
+ gpointer singleton_location = &calendar_sources_singleton;
+
+ if (calendar_sources_singleton)
+ return g_object_ref (calendar_sources_singleton);
+
+ calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL);
+ g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton),
+ singleton_location);
+
+ return calendar_sources_singleton;
+}
+
+static gboolean
+is_source_selected (ESource *esource,
+ GSList *selected_sources)
+{
+ const char *uid;
+ GSList *l;
+
+ uid = e_source_peek_uid (esource);
+
+ for (l = selected_sources; l; l = l->next)
+ {
+ const char *source = l->data;
+
+ if (!strcmp (source, uid))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *
+auth_func_cb (ECal *ecal,
+ const char *prompt,
+ const char *key,
+ gpointer user_data)
+{
+ ESource *source;
+ const gchar *auth_domain;
+ const gchar *component_name;
+
+ source = e_cal_get_source (ecal);
+ auth_domain = e_source_get_property (source, "auth-domain");
+ component_name = auth_domain ? auth_domain : "Calendar";
+
+ return e_passwords_get_password (component_name, key);
+}
+
+/* The clients are just created here but not loaded */
+static ECal *
+get_ecal_from_source (ESource *esource,
+ ECalSourceType source_type,
+ GSList *existing_clients)
+{
+ ECal *retval;
+
+ if (existing_clients)
+ {
+ GSList *l;
+
+ for (l = existing_clients; l; l = l->next)
+ {
+ ECal *client = E_CAL (l->data);
+
+ if (e_source_equal (esource, e_cal_get_source (client)))
+ {
+ dprintf (" load_esource: found existing source ... returning that\n");
+
+ return g_object_ref (client);
+ }
+ }
+ }
+
+ retval = e_cal_new (esource, source_type);
+ if (!retval)
+ {
+ g_warning ("Could not load source '%s' from '%s'\n",
+ e_source_peek_name (esource),
+ e_source_peek_relative_uri (esource));
+ return NULL;
+ }
+
+ e_cal_set_auth_func (retval, auth_func_cb, NULL);
+
+ return retval;
+}
+
+/* - Order doesn't matter
+ * - Can just compare object pointers since we
+ * re-use client connections
+ */
+static gboolean
+compare_ecal_lists (GSList *a,
+ GSList *b)
+{
+ GSList *l;
+
+ if (g_slist_length (a) != g_slist_length (b))
+ return FALSE;
+
+ for (l = a; l; l = l->next)
+ {
+ if (!g_slist_find (b, l->data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline void
+debug_dump_selected_sources (GSList *selected_sources)
+{
+#ifdef CALENDAR_ENABLE_DEBUG
+ GSList *l;
+
+ dprintf ("Selected sources:\n");
+ for (l = selected_sources; l; l = l->next)
+ {
+ char *source = l->data;
+
+ dprintf (" %s\n", source);
+ }
+ dprintf ("\n");
+#endif
+}
+
+static inline void
+debug_dump_ecal_list (GSList *ecal_list)
+{
+#ifdef CALENDAR_ENABLE_DEBUG
+ GSList *l;
+
+ dprintf ("Loaded clients:\n");
+ for (l = ecal_list; l; l = l->next)
+ {
+ ECal *client = l->data;
+ ESource *source = e_cal_get_source (client);
+
+ dprintf (" %s %s %s\n",
+ e_source_peek_uid (source),
+ e_source_peek_name (source),
+ e_cal_get_uri (client));
+ }
+#endif
+}
+
+static void
+calendar_sources_load_esource_list (CalendarSourceData *source_data);
+
+static gboolean
+backend_restart (gpointer data)
+{
+ CalendarSourceData *source_data = data;
+
+ calendar_sources_load_esource_list (source_data);
+
+ source_data->timeout_id = 0;
+
+ return FALSE;
+}
+
+static void
+backend_died_cb (ECal *client, CalendarSourceData *source_data)
+{
+ const char *uristr;
+
+ source_data->clients = g_slist_remove (source_data->clients, client);
+ if (g_slist_length (source_data->clients) < 1)
+ {
+ g_slist_free (source_data->clients);
+ source_data->clients = NULL;
+ }
+ uristr = e_cal_get_uri (client);
+ g_warning ("The calendar backend for %s has crashed.", uristr);
+
+ if (source_data->timeout_id != 0)
+ {
+ g_source_remove (source_data->timeout_id);
+ source_data->timeout_id = 0;
+ }
+
+ source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
+ source_data);
+}
+
+static void
+calendar_sources_load_esource_list (CalendarSourceData *source_data)
+{
+ GSList *clients = NULL;
+ GSList *groups, *l;
+ gboolean emit_signal = FALSE;
+
+ g_return_if_fail (source_data->esource_list != NULL);
+
+ debug_dump_selected_sources (source_data->selected_sources);
+
+ dprintf ("Source groups:\n");
+ groups = e_source_list_peek_groups (source_data->esource_list);
+ for (l = groups; l; l = l->next)
+ {
+ GSList *esources, *s;
+
+ dprintf (" %s\n", e_source_group_peek_uid (l->data));
+ dprintf (" sources:\n");
+
+ esources = e_source_group_peek_sources (l->data);
+ for (s = esources; s; s = s->next)
+ {
+ ESource *esource = E_SOURCE (s->data);
+ ECal *client;
+
+ dprintf (" type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
+ source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task",
+ e_source_peek_uid (esource),
+ e_source_peek_name (esource),
+ e_source_peek_relative_uri (esource));
+
+ if (is_source_selected (esource, source_data->selected_sources) &&
+ (client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
+ {
+ clients = g_slist_prepend (clients, client);
+ }
+ }
+ }
+ dprintf ("\n");
+
+ if (source_data->loaded &&
+ !compare_ecal_lists (source_data->clients, clients))
+ emit_signal = TRUE;
+
+ for (l = source_data->clients; l; l = l->next)
+ {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
+ G_CALLBACK (backend_died_cb),
+ source_data);
+
+ g_object_unref (l->data);
+ }
+ g_slist_free (source_data->clients);
+ source_data->clients = g_slist_reverse (clients);
+
+ /* connect to backend_died after we disconnected the previous signal
+ * handlers. If we do it before, we'll lose some handlers (for clients that
+ * were already there before) */
+ for (l = source_data->clients; l; l = l->next)
+ {
+ g_signal_connect (G_OBJECT (l->data), "backend_died",
+ G_CALLBACK (backend_died_cb), source_data);
+ }
+
+ if (emit_signal)
+ {
+ dprintf ("Emitting %s-sources-changed signal\n",
+ source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task");
+ g_signal_emit (source_data->sources, source_data->changed_signal, 0);
+ }
+
+ debug_dump_ecal_list (source_data->clients);
+}
+
+static void
+calendar_sources_esource_list_changed (ESourceList *source_list,
+ CalendarSourceData *source_data)
+
+{
+ dprintf ("ESourceList changed, reloading\n");
+
+ calendar_sources_load_esource_list (source_data);
+}
+
+static void
+calendar_sources_selected_sources_notify (GConfClient *client,
+ guint cnx_id,
+ GConfEntry *entry,
+ CalendarSourceData *source_data)
+{
+ GSList *l;
+
+ if (!entry->value ||
+ entry->value->type != GCONF_VALUE_LIST ||
+ gconf_value_get_list_type (entry->value) != GCONF_VALUE_STRING)
+ return;
+
+ dprintf ("Selected sources key (%s) changed, reloading\n", entry->key);
+
+ for (l = source_data->selected_sources; l; l = l->next)
+ g_free (l->data);
+ source_data->selected_sources = NULL;
+
+ for (l = gconf_value_get_list (entry->value); l; l = l->next)
+ {
+ const char *source = gconf_value_get_string (l->data);
+
+ source_data->selected_sources =
+ g_slist_prepend (source_data->selected_sources,
+ g_strdup (source));
+ }
+ source_data->selected_sources =
+ g_slist_reverse (source_data->selected_sources);
+
+ calendar_sources_load_esource_list (source_data);
+}
+
+static void
+calendar_sources_load_sources (CalendarSources *sources,
+ CalendarSourceData *source_data,
+ const char *sources_key,
+ const char *selected_sources_key,
+ const char *selected_sources_dir)
+{
+ GConfClient *gconf_client;
+ GError *error;
+
+ dprintf ("---------------------------\n");
+ dprintf ("Loading sources:\n");
+ dprintf (" sources_key: %s\n", sources_key);
+ dprintf (" selected_sources_key: %s\n", selected_sources_key);
+ dprintf (" selected_sources_dir: %s\n", selected_sources_dir);
+
+ gconf_client = sources->priv->gconf_client;
+
+ error = NULL;
+ source_data->selected_sources = gconf_client_get_list (gconf_client,
+ selected_sources_key,
+ GCONF_VALUE_STRING,
+ &error);
+ if (error)
+ {
+ g_warning ("Failed to get selected sources from '%s': %s\n",
+ selected_sources_key,
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ gconf_client_add_dir (gconf_client,
+ selected_sources_dir,
+ GCONF_CLIENT_PRELOAD_NONE,
+ NULL);
+ source_data->selected_sources_dir = g_strdup (selected_sources_dir);
+
+ source_data->selected_sources_listener =
+ gconf_client_notify_add (gconf_client,
+ selected_sources_dir,
+ (GConfClientNotifyFunc) calendar_sources_selected_sources_notify,
+ source_data, NULL, NULL);
+
+ source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
+ g_signal_connect (source_data->esource_list, "changed",
+ G_CALLBACK (calendar_sources_esource_list_changed),
+ source_data);
+
+ calendar_sources_load_esource_list (source_data);
+
+ source_data->loaded = TRUE;
+
+ dprintf ("---------------------------\n");
+}
+
+GSList *
+calendar_sources_get_appointment_sources (CalendarSources *sources)
+{
+ g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
+
+ if (!sources->priv->appointment_sources.loaded)
+ {
+ calendar_sources_load_sources (sources,
+ &sources->priv->appointment_sources,
+ CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
+ CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY,
+ CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR);
+ }
+
+ return sources->priv->appointment_sources.clients;
+}
+
+GSList *
+calendar_sources_get_task_sources (CalendarSources *sources)
+{
+ g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
+
+ if (!sources->priv->task_sources.loaded)
+ {
+ calendar_sources_load_sources (sources,
+ &sources->priv->task_sources,
+ CALENDAR_SOURCES_TASK_SOURCES_KEY,
+ CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY,
+ CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR);
+ }
+
+ return sources->priv->task_sources.clients;
+}
--- /dev/null
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ * Mark McLoughlin <mark@skynet.ie>
+ * William Jon McCann <mccann@jhu.edu>
+ * Martin Grimme <martin@pycage.de>
+ * Christian Kellner <gicmo@xatom.net>
+ */
+
+#ifndef __CALENDAR_SOURCES_H__
+#define __CALENDAR_SOURCES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ())
+#define CALENDAR_SOURCES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources))
+#define CALENDAR_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
+#define CALENDAR_IS_SOURCES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES))
+#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES))
+#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
+
+typedef struct _CalendarSources CalendarSources;
+typedef struct _CalendarSourcesClass CalendarSourcesClass;
+typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
+
+struct _CalendarSources
+{
+ GObject parent;
+ CalendarSourcesPrivate *priv;
+};
+
+struct _CalendarSourcesClass
+{
+ GObjectClass parent_class;
+
+ void (* appointment_sources_changed) (CalendarSources *sources);
+ void (* task_sources_changed) (CalendarSources *sources);
+};
+
+
+GType calendar_sources_get_type (void) G_GNUC_CONST;
+CalendarSources *calendar_sources_get (void);
+GSList *calendar_sources_get_appointment_sources (CalendarSources *sources);
+GSList *calendar_sources_get_task_sources (CalendarSources *sources);
+
+G_END_DECLS
+
+#endif /* __CALENDAR_SOURCES_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ *
+ * Based on code from gnome-panel's clock-applet, file calendar-client.c, with Authors:
+ *
+ * Mark McLoughlin <mark@skynet.ie>
+ * William Jon McCann <mccann@jhu.edu>
+ * Martin Grimme <martin@pycage.de>
+ * Christian Kellner <gicmo@xatom.net>
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gio/gio.h>
+
+#define HANDLE_LIBICAL_MEMORY
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+#include <libecal/e-cal-recur.h>
+#include <libecal/e-cal-system-timezone.h>
+
+#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
+#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
+
+#include "calendar-sources.h"
+
+/* Set the environment variable CALENDAR_SERVER_DEBUG to show debug */
+static void print_debug (const gchar *str, ...);
+
+#define BUS_NAME "org.gnome.Shell.CalendarServer"
+
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='org.gnome.Shell.CalendarServer'>"
+ " <method name='GetEvents'>"
+ " <arg type='x' name='since' direction='in'/>"
+ " <arg type='x' name='until' direction='in'/>"
+ " <arg type='b' name='force_reload' direction='in'/>"
+ " <arg type='a(sssbxxa{sv})' name='events' direction='out'/>"
+ " </method>"
+ " <signal name='Changed'/>"
+ " <property name='Since' type='x' access='read'/>"
+ " <property name='Until' type='x' access='read'/>"
+ " </interface>"
+ "</node>";
+static GDBusNodeInfo *introspection_data = NULL;
+
+struct _App;
+typedef struct _App App;
+
+static GMainLoop *loop = NULL;
+static gboolean opt_replace = FALSE;
+static GOptionEntry opt_entries[] = {
+ {"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
+ {NULL }
+};
+static App *_global_app = NULL;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ time_t start_time;
+ time_t end_time;
+} CalendarOccurrence;
+
+typedef struct
+{
+ char *uid;
+ char *rid;
+ char *uri;
+ char *summary;
+ char *description;
+ char *color_string;
+ time_t start_time;
+ time_t end_time;
+ guint is_all_day : 1;
+
+ /* Only used internally */
+ GSList *occurrences;
+} CalendarAppointment;
+
+static time_t
+get_time_from_property (icalcomponent *ical,
+ icalproperty_kind prop_kind,
+ struct icaltimetype (* get_prop_func) (const icalproperty *prop),
+ icaltimezone *default_zone)
+{
+ icalproperty *prop;
+ struct icaltimetype ical_time;
+ icalparameter *param;
+ icaltimezone *timezone = NULL;
+
+ prop = icalcomponent_get_first_property (ical, prop_kind);
+ if (!prop)
+ return 0;
+
+ ical_time = get_prop_func (prop);
+
+ param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
+ if (param)
+ timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
+ else if (icaltime_is_utc (ical_time))
+ timezone = icaltimezone_get_utc_timezone ();
+ else
+ timezone = default_zone;
+
+ return icaltime_as_timet_with_zone (ical_time, timezone);
+}
+
+static char *
+get_ical_uid (icalcomponent *ical)
+{
+ return g_strdup (icalcomponent_get_uid (ical));
+}
+
+static char *
+get_ical_rid (icalcomponent *ical)
+{
+ icalproperty *prop;
+ struct icaltimetype ical_time;
+
+ prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
+ if (!prop)
+ return NULL;
+
+ ical_time = icalproperty_get_recurrenceid (prop);
+
+ return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ?
+ g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
+}
+
+static char *
+get_ical_summary (icalcomponent *ical)
+{
+ icalproperty *prop;
+
+ prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
+ if (!prop)
+ return NULL;
+
+ return g_strdup (icalproperty_get_summary (prop));
+}
+
+static char *
+get_ical_description (icalcomponent *ical)
+{
+ icalproperty *prop;
+
+ prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
+ if (!prop)
+ return NULL;
+
+ return g_strdup (icalproperty_get_description (prop));
+}
+
+static inline time_t
+get_ical_start_time (icalcomponent *ical,
+ icaltimezone *default_zone)
+{
+ return get_time_from_property (ical,
+ ICAL_DTSTART_PROPERTY,
+ icalproperty_get_dtstart,
+ default_zone);
+}
+
+static inline time_t
+get_ical_end_time (icalcomponent *ical,
+ icaltimezone *default_zone)
+{
+ return get_time_from_property (ical,
+ ICAL_DTEND_PROPERTY,
+ icalproperty_get_dtend,
+ default_zone);
+}
+
+static gboolean
+get_ical_is_all_day (icalcomponent *ical,
+ time_t start_time,
+ icaltimezone *default_zone)
+{
+ icalproperty *prop;
+ struct tm *start_tm;
+ time_t end_time;
+ struct icaldurationtype duration;
+ struct icaltimetype start_icaltime;
+
+ start_icaltime = icalcomponent_get_dtstart (ical);
+ if (start_icaltime.is_date)
+ return TRUE;
+
+ start_tm = gmtime (&start_time);
+ if (start_tm->tm_sec != 0 ||
+ start_tm->tm_min != 0 ||
+ start_tm->tm_hour != 0)
+ return FALSE;
+
+ if ((end_time = get_ical_end_time (ical, default_zone)))
+ return (end_time - start_time) % 86400 == 0;
+
+ prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
+ if (!prop)
+ return FALSE;
+
+ duration = icalproperty_get_duration (prop);
+
+ return icaldurationtype_as_int (duration) % 86400 == 0;
+}
+
+static inline time_t
+get_ical_due_time (icalcomponent *ical,
+ icaltimezone *default_zone)
+{
+ return get_time_from_property (ical,
+ ICAL_DUE_PROPERTY,
+ icalproperty_get_due,
+ default_zone);
+}
+
+static inline time_t
+get_ical_completed_time (icalcomponent *ical,
+ icaltimezone *default_zone)
+{
+ return get_time_from_property (ical,
+ ICAL_COMPLETED_PROPERTY,
+ icalproperty_get_completed,
+ default_zone);
+}
+
+static char *
+get_source_color (ECal *esource)
+{
+ ESource *source;
+
+ g_return_val_if_fail (E_IS_CAL (esource), NULL);
+
+ source = e_cal_get_source (esource);
+
+ return g_strdup (e_source_peek_color_spec (source));
+}
+
+static gchar *
+get_source_uri (ECal *esource)
+{
+ ESource *source;
+ gchar *string;
+ gchar **list;
+
+ g_return_val_if_fail (E_IS_CAL (esource), NULL);
+
+ source = e_cal_get_source (esource);
+ string = g_strdup (e_source_get_uri (source));
+ if (string) {
+ list = g_strsplit (string, ":", 2);
+ g_free (string);
+
+ if (list[0]) {
+ string = g_strdup (list[0]);
+ g_strfreev (list);
+ return string;
+ }
+ g_strfreev (list);
+ }
+ return NULL;
+}
+
+static inline int
+null_safe_strcmp (const char *a,
+ const char *b)
+{
+ return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
+}
+
+static inline gboolean
+calendar_appointment_equal (CalendarAppointment *a,
+ CalendarAppointment *b)
+{
+ GSList *la, *lb;
+
+ if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
+ return FALSE;
+
+ for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
+ {
+ CalendarOccurrence *oa = la->data;
+ CalendarOccurrence *ob = lb->data;
+
+ if (oa->start_time != ob->start_time ||
+ oa->end_time != ob->end_time)
+ return FALSE;
+ }
+
+ return
+ null_safe_strcmp (a->uid, b->uid) == 0 &&
+ null_safe_strcmp (a->uri, b->uri) == 0 &&
+ null_safe_strcmp (a->summary, b->summary) == 0 &&
+ null_safe_strcmp (a->description, b->description) == 0 &&
+ null_safe_strcmp (a->color_string, b->color_string) == 0 &&
+ a->start_time == b->start_time &&
+ a->end_time == b->end_time &&
+ a->is_all_day == b->is_all_day;
+}
+
+static void
+calendar_appointment_free (CalendarAppointment *appointment)
+{
+ GSList *l;
+
+ for (l = appointment->occurrences; l; l = l->next)
+ g_free (l->data);
+ g_slist_free (appointment->occurrences);
+ appointment->occurrences = NULL;
+
+ g_free (appointment->uid);
+ appointment->uid = NULL;
+
+ g_free (appointment->rid);
+ appointment->rid = NULL;
+
+ g_free (appointment->uri);
+ appointment->uri = NULL;
+
+ g_free (appointment->summary);
+ appointment->summary = NULL;
+
+ g_free (appointment->description);
+ appointment->description = NULL;
+
+ g_free (appointment->color_string);
+ appointment->color_string = NULL;
+
+ appointment->start_time = 0;
+ appointment->is_all_day = FALSE;
+}
+
+static void
+calendar_appointment_init (CalendarAppointment *appointment,
+ icalcomponent *ical,
+ ECal *cal,
+ icaltimezone *default_zone)
+{
+ appointment->uid = get_ical_uid (ical);
+ appointment->rid = get_ical_rid (ical);
+ appointment->uri = get_source_uri (cal);
+ appointment->summary = get_ical_summary (ical);
+ appointment->description = get_ical_description (ical);
+ appointment->color_string = get_source_color (cal);
+ appointment->start_time = get_ical_start_time (ical, default_zone);
+ appointment->end_time = get_ical_end_time (ical, default_zone);
+ appointment->is_all_day = get_ical_is_all_day (ical,
+ appointment->start_time,
+ default_zone);
+}
+
+static icaltimezone *
+resolve_timezone_id (const char *tzid,
+ ECal *source)
+{
+ icaltimezone *retval;
+
+ retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+ if (!retval)
+ {
+ e_cal_get_timezone (source, tzid, &retval, NULL);
+ }
+
+ return retval;
+}
+
+static gboolean
+calendar_appointment_collect_occurrence (ECalComponent *component,
+ time_t occurrence_start,
+ time_t occurrence_end,
+ gpointer data)
+{
+ CalendarOccurrence *occurrence;
+ GSList **collect_loc = data;
+
+ occurrence = g_new0 (CalendarOccurrence, 1);
+ occurrence->start_time = occurrence_start;
+ occurrence->end_time = occurrence_end;
+
+ *collect_loc = g_slist_prepend (*collect_loc, occurrence);
+
+ return TRUE;
+}
+
+static void
+calendar_appointment_generate_occurrences (CalendarAppointment *appointment,
+ icalcomponent *ical,
+ ECal *cal,
+ time_t start,
+ time_t end,
+ icaltimezone *default_zone)
+{
+ ECalComponent *ecal;
+
+ g_assert (appointment->occurrences == NULL);
+
+ ecal = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (ecal,
+ icalcomponent_new_clone (ical));
+
+ e_cal_recur_generate_instances (ecal,
+ start,
+ end,
+ calendar_appointment_collect_occurrence,
+ &appointment->occurrences,
+ (ECalRecurResolveTimezoneFn) resolve_timezone_id,
+ cal,
+ default_zone);
+
+ g_object_unref (ecal);
+
+ appointment->occurrences = g_slist_reverse (appointment->occurrences);
+}
+
+static CalendarAppointment *
+calendar_appointment_new (icalcomponent *ical,
+ ECal *cal,
+ icaltimezone *default_zone)
+{
+ CalendarAppointment *appointment;
+
+ appointment = g_new0 (CalendarAppointment, 1);
+
+ calendar_appointment_init (appointment,
+ ical,
+ cal,
+ default_zone);
+ return appointment;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct _App
+{
+ GDBusConnection *connection;
+
+ time_t since;
+ time_t until;
+
+ icaltimezone *zone;
+
+ CalendarSources *sources;
+ gulong sources_signal_id;
+
+ guint zone_listener;
+ GConfClient *gconf_client;
+
+ /* hash from uid to CalendarAppointment objects */
+ GHashTable *appointments;
+
+ gchar *timezone_location;
+
+ guint changed_timeout_id;
+
+ gboolean cache_invalid;
+
+ GList *live_views;
+};
+
+static void
+app_update_timezone (App *app)
+{
+ gchar *location;
+
+ location = e_cal_system_timezone_get_location ();
+ if (g_strcmp0 (location, app->timezone_location) != 0)
+ {
+ if (location == NULL)
+ app->zone = icaltimezone_get_utc_timezone ();
+ else
+ app->zone = icaltimezone_get_builtin_timezone (location);
+ g_free (app->timezone_location);
+ app->timezone_location = location;
+ print_debug ("Using timezone %s", app->timezone_location);
+ }
+}
+
+static gboolean
+on_app_schedule_changed_cb (gpointer user_data)
+{
+ App *app = user_data;
+ print_debug ("Emitting changed");
+ g_dbus_connection_emit_signal (app->connection,
+ NULL, /* destination_bus_name */
+ "/org/gnome/Shell/CalendarServer",
+ "org.gnome.Shell.CalendarServer",
+ "Changed",
+ NULL, /* no params */
+ NULL);
+ app->changed_timeout_id = 0;
+ return FALSE;
+}
+
+static void
+app_schedule_changed (App *app)
+{
+ print_debug ("Scheduling changed");
+ if (app->changed_timeout_id == 0)
+ {
+ app->changed_timeout_id = g_timeout_add (2000,
+ on_app_schedule_changed_cb,
+ app);
+ }
+}
+
+static void
+invalidate_cache (App *app)
+{
+ app->cache_invalid = TRUE;
+}
+
+static void
+on_objects_added (ECalView *view,
+ GList *objects,
+ gpointer user_data)
+{
+ App *app = user_data;
+ GList *l;
+
+ print_debug ("%s for calendar", G_STRFUNC);
+
+ for (l = objects; l != NULL; l = l->next)
+ {
+ icalcomponent *ical = l->data;
+ const char *uid;
+
+ uid = icalcomponent_get_uid (ical);
+
+ if (g_hash_table_lookup (app->appointments, uid) == NULL)
+ {
+ /* new appointment we don't know about => changed signal */
+ invalidate_cache (app);
+ app_schedule_changed (app);
+ }
+ }
+}
+
+static void
+on_objects_modified (ECalView *view,
+ GList *objects,
+ gpointer user_data)
+{
+ App *app = user_data;
+ print_debug ("%s for calendar", G_STRFUNC);
+ invalidate_cache (app);
+ app_schedule_changed (app);
+}
+
+static void
+on_objects_removed (ECalView *view,
+ GList *uids,
+ gpointer user_data)
+{
+ App *app = user_data;
+ print_debug ("%s for calendar", G_STRFUNC);
+ invalidate_cache (app);
+ app_schedule_changed (app);
+}
+
+static void
+app_load_events (App *app)
+{
+ GSList *sources;
+ GSList *l;
+ GList *ll;
+ gchar *since_iso8601;
+ gchar *until_iso8601;
+
+ /* out with the old */
+ g_hash_table_remove_all (app->appointments);
+ /* nuke existing views */
+ for (ll = app->live_views; ll != NULL; ll = ll->next)
+ {
+ ECalView *view = E_CAL_VIEW (ll->data);
+ g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
+ g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
+ g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
+ e_cal_view_stop (view);
+ g_object_unref (view);
+ }
+ g_list_free (app->live_views);
+ app->live_views = NULL;
+
+ /* timezone could have changed */
+ app_update_timezone (app);
+
+ since_iso8601 = isodate_from_time_t (app->since);
+ until_iso8601 = isodate_from_time_t (app->until);
+
+ print_debug ("Loading events since %s until %s",
+ since_iso8601,
+ until_iso8601);
+
+ sources = calendar_sources_get_appointment_sources (app->sources);
+ for (l = sources; l != NULL; l = l->next)
+ {
+ ECal *cal = E_CAL (l->data);
+ GError *error;
+ gchar *query;
+ GList *objects;
+ GList *j;
+ ECalView *view;
+
+ error = NULL;
+ if (!e_cal_set_default_timezone (cal, app->zone, &error))
+ {
+ g_printerr ("Error setting timezone on calendar: %s\n", error->message);
+ g_error_free (error);
+ continue;
+ }
+
+ error = NULL;
+ if (!e_cal_open (cal, TRUE, &error))
+ {
+ g_printerr ("Error opening calendar: %s\n", error->message);
+ g_error_free (error);
+ continue;
+ }
+
+ query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
+ "(make-time \"%s\")",
+ since_iso8601,
+ until_iso8601);
+ error = NULL;
+ objects = NULL;
+ if (!e_cal_get_object_list (cal,
+ query,
+ &objects,
+ &error))
+ {
+ g_printerr ("Error querying calendar: %s\n", error->message);
+ g_error_free (error);
+ g_free (query);
+ continue;
+ }
+
+ for (j = objects; j != NULL; j = j->next)
+ {
+ icalcomponent *ical = j->data;
+ CalendarAppointment *appointment;
+
+ appointment = calendar_appointment_new (ical, cal, app->zone);
+ if (appointment == NULL)
+ continue;
+
+ calendar_appointment_generate_occurrences (appointment,
+ ical,
+ cal,
+ app->since,
+ app->until,
+ app->zone);
+ g_hash_table_insert (app->appointments, g_strdup (appointment->uid), appointment);
+ }
+
+ e_cal_free_object_list (objects);
+
+ error = NULL;
+ if (!e_cal_get_query (cal,
+ query,
+ &view,
+ &error))
+ {
+ g_printerr ("Error setting up live-query on calendar: %s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_signal_connect (view,
+ "objects-added",
+ G_CALLBACK (on_objects_added),
+ app);
+ g_signal_connect (view,
+ "objects-modified",
+ G_CALLBACK (on_objects_modified),
+ app);
+ g_signal_connect (view,
+ "objects-removed",
+ G_CALLBACK (on_objects_removed),
+ app);
+ e_cal_view_start (view);
+ app->live_views = g_list_prepend (app->live_views, view);
+ }
+
+ g_free (query);
+ }
+ g_free (since_iso8601);
+ g_free (until_iso8601);
+ app->cache_invalid = FALSE;
+}
+
+static void
+on_appointment_sources_changed (CalendarSources *sources,
+ gpointer user_data)
+{
+ App *app = user_data;
+
+ print_debug ("Sources changed\n");
+ app_load_events (app);
+}
+
+static App *
+app_new (GDBusConnection *connection)
+{
+ App *app;
+
+ app = g_new0 (App, 1);
+ app->connection = g_object_ref (connection);
+ app->sources = calendar_sources_get ();
+ app->sources_signal_id = g_signal_connect (app->sources,
+ "appointment-sources-changed",
+ G_CALLBACK (on_appointment_sources_changed),
+ app);
+
+ app->appointments = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) calendar_appointment_free);
+
+ app_update_timezone (app);
+
+ return app;
+}
+
+static void
+app_free (App *app)
+{
+ GList *ll;
+ for (ll = app->live_views; ll != NULL; ll = ll->next)
+ {
+ ECalView *view = E_CAL_VIEW (ll->data);
+ g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
+ g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
+ g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
+ e_cal_view_stop (view);
+ g_object_unref (view);
+ }
+ g_list_free (app->live_views);
+
+ g_free (app->timezone_location);
+
+ g_hash_table_unref (app->appointments);
+
+ g_object_unref (app->connection);
+ g_signal_handler_disconnect (app->sources,
+ app->sources_signal_id);
+ g_object_unref (app->sources);
+
+ if (app->changed_timeout_id != 0)
+ g_source_remove (app->changed_timeout_id);
+
+ g_free (app);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ App *app = user_data;
+
+ if (g_strcmp0 (method_name, "GetEvents") == 0)
+ {
+ GVariantBuilder builder;
+ GHashTableIter hash_iter;
+ CalendarAppointment *a;
+ gint64 since;
+ gint64 until;
+ gboolean force_reload;
+ gboolean window_changed;
+
+ g_variant_get (parameters,
+ "(xxb)",
+ &since,
+ &until,
+ &force_reload);
+
+ if (until < since)
+ {
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ "org.gnome.Shell.CalendarServer.Error.Failed",
+ "until cannot be before since");
+ goto out;
+ }
+
+ print_debug ("Handling GetEvents (since=%" G_GINT64_FORMAT ", until=%" G_GINT64_FORMAT ", force_reload=%s)",
+ since,
+ until,
+ force_reload ? "true" : "false");
+
+ window_changed = FALSE;
+ if (!(app->until == until && app->since == since))
+ {
+ GVariantBuilder *builder;
+ GVariantBuilder *invalidated_builder;
+
+ app->until = until;
+ app->since = since;
+ window_changed = TRUE;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+ invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+ g_variant_builder_add (builder, "{sv}",
+ "Until", g_variant_new_int64 (app->until));
+ g_variant_builder_add (builder, "{sv}",
+ "Since", g_variant_new_int64 (app->since));
+ g_dbus_connection_emit_signal (app->connection,
+ NULL, /* destination_bus_name */
+ "/org/gnome/Shell/CalendarServer",
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new ("(sa{sv}as)",
+ "org.gnome.Shell.CalendarServer",
+ builder,
+ invalidated_builder),
+ NULL); /* GError** */
+ }
+
+ /* reload events if necessary */
+ if (window_changed || force_reload || app->cache_invalid)
+ {
+ app_load_events (app);
+ }
+
+ /* The a{sv} is used as an escape hatch in case we want to provide more
+ * information in the future without breaking ABI
+ */
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssbxxa{sv})"));
+ g_hash_table_iter_init (&hash_iter, app->appointments);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &a))
+ {
+ GVariantBuilder extras_builder;
+ GSList *l;
+
+ for (l = a->occurrences; l; l = l->next)
+ {
+ CalendarOccurrence *o = l->data;
+ time_t start_time = o->start_time;
+ time_t end_time = o->end_time;
+
+ if ((start_time >= app->since &&
+ start_time < app->until) ||
+ (start_time <= app->since &&
+ (end_time - 1) > app->since))
+ {
+ g_variant_builder_init (&extras_builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&builder,
+ "(sssbxxa{sv})",
+ a->uid,
+ a->summary != NULL ? a->summary : "",
+ a->description != NULL ? a->description : "",
+ (gboolean) a->is_all_day,
+ (gint64) start_time,
+ (gint64) end_time,
+ extras_builder);
+ }
+ }
+ }
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(a(sssbxxa{sv}))", &builder));
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ out:
+ ;
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ App *app = user_data;
+ GVariant *ret;
+
+ ret = NULL;
+ if (g_strcmp0 (property_name, "Since") == 0)
+ {
+ ret = g_variant_new_int64 (app->since);
+ }
+ else if (g_strcmp0 (property_name, "Until") == 0)
+ {
+ ret = g_variant_new_int64 (app->until);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ return ret;
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ handle_get_property,
+ NULL /* handle_set_property */
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GError *error;
+ guint registration_id;
+
+ _global_app = app_new (connection);
+
+ error = NULL;
+ registration_id = g_dbus_connection_register_object (connection,
+ "/org/gnome/Shell/CalendarServer",
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ _global_app,
+ NULL, /* user_data_free_func */
+ &error);
+ if (registration_id == 0)
+ {
+ g_printerr ("Error exporting object: %s (%s %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ _exit (1);
+ }
+
+ print_debug ("Connected to the session bus");
+
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_print ("gnome-shell-calendar-server[%d]: Lost (or failed to acquire) the name " BUS_NAME " - exiting\n",
+ (gint) getpid ());
+ g_main_loop_quit (loop);
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ print_debug ("Acquired the name " BUS_NAME);
+}
+
+static gboolean
+stdin_channel_io_func (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ if (condition & G_IO_HUP)
+ {
+ g_print ("gnome-shell-calendar-server[%d]: Got HUP on stdin - exiting\n",
+ (gint) getpid ());
+ g_main_loop_quit (loop);
+ }
+ else
+ {
+ g_warning ("Unhandled condition %d on GIOChannel for stdin", condition);
+ }
+ return FALSE; /* remove source */
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GError *error;
+ GOptionContext *opt_context;
+ gint ret;
+ guint name_owner_id;
+ GIOChannel *stdin_channel;
+
+ ret = 1;
+ loop = NULL;
+ opt_context = NULL;
+ name_owner_id = 0;
+
+ g_type_init ();
+
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+ g_assert (introspection_data != NULL);
+
+ opt_context = g_option_context_new ("gnome-shell calendar server");
+ g_option_context_add_main_entries (opt_context, opt_entries, NULL);
+ error = NULL;
+ if (!g_option_context_parse (opt_context, &argc, &argv, &error))
+ {
+ g_printerr ("Error parsing options: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
+ g_io_add_watch (stdin_channel,
+ G_IO_HUP,
+ stdin_channel_io_func,
+ NULL);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+ (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL,
+ NULL);
+
+ g_main_loop_run (loop);
+
+ ret = 0;
+
+ out:
+ if (stdin_channel != NULL)
+ g_io_channel_unref (stdin_channel);
+ if (_global_app != NULL)
+ app_free (_global_app);
+ if (name_owner_id != 0)
+ g_bus_unown_name (name_owner_id);
+ if (loop != NULL)
+ g_main_loop_unref (loop);
+ if (opt_context != NULL)
+ g_option_context_free (opt_context);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+print_debug (const gchar *format, ...)
+{
+ gchar *s;
+ va_list ap;
+ gchar timebuf[64];
+ GTimeVal now;
+ time_t now_t;
+ struct tm broken_down;
+ static volatile gsize once_init_value = 0;
+ static gboolean show_debug = FALSE;
+ static guint pid = 0;
+
+ if (g_once_init_enter (&once_init_value))
+ {
+ show_debug = (g_getenv ("CALENDAR_SERVER_DEBUG") != NULL);
+ pid = getpid ();
+ g_once_init_leave (&once_init_value, 1);
+ }
+
+ if (!show_debug)
+ goto out;
+
+ g_get_current_time (&now);
+ now_t = now.tv_sec;
+ localtime_r (&now_t, &broken_down);
+ strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
+
+ va_start (ap, format);
+ s = g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ g_print ("gnome-shell-calendar-server[%d]: %s.%03d: %s\n", pid, timebuf, (gint) (now.tv_usec / 1000), s);
+ g_free (s);
+ out:
+ ;
+}
--- /dev/null
+[D-BUS Service]
+Name=org.gnome.Shell.CalendarServer
+Exec=@libexecdir@/gnome-shell-calendar-server
if running_from_source_tree:
if os.environ.has_key('GI_TYPELIB_PATH'):
typelib_dir = typelib_dir + ":" + os.environ.get('GI_TYPELIB_PATH')
- env.update({'GNOME_SHELL_DATADIR' : data_dir,
+ env.update({'GNOME_SHELL_BINDIR' : bin_dir,
+ 'GNOME_SHELL_DATADIR' : data_dir,
'GI_TYPELIB_PATH' : typelib_dir,
'GSETTINGS_SCHEMA_DIR' : data_dir })
else:
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#include "config.h"
-
-#include "calendar-client/calendar-client.h"
-#include "shell-evolution-event-source.h"
-
-
-struct _ShellEvolutionEventSourceClass
-{
- GObjectClass parent_class;
-};
-
-struct _ShellEvolutionEventSource {
- GObject parent;
- CalendarClient *client;
- /* The month that we are currently requesting events from */
- gint req_year;
- gint req_mon; /* starts at 1, not zero */
-};
-
-/* Signals */
-enum
-{
- CHANGED_SIGNAL,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (ShellEvolutionEventSource, shell_evolution_event_source, G_TYPE_OBJECT);
-
-static void
-on_tasks_changed (CalendarClient *client,
- gpointer user_data)
-{
- ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
- /* g_print ("on tasks changed\n"); */
- g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
-}
-
-static void
-on_appointments_changed (CalendarClient *client,
- gpointer user_data)
-{
- ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
- /* g_print ("on appointments changed\n"); */
- g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
-}
-
-static void
-shell_evolution_event_source_init (ShellEvolutionEventSource *source)
-{
- source->client = calendar_client_new ();
- g_signal_connect (source->client,
- "tasks-changed",
- G_CALLBACK (on_tasks_changed),
- source);
- g_signal_connect (source->client,
- "appointments-changed",
- G_CALLBACK (on_appointments_changed),
- source);
-}
-
-static void
-shell_evolution_event_source_finalize (GObject *object)
-{
- ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (object);
- g_object_unref (source->client);
- G_OBJECT_CLASS (shell_evolution_event_source_parent_class)->finalize (object);
-}
-
-static void
-shell_evolution_event_source_class_init (ShellEvolutionEventSourceClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->finalize = shell_evolution_event_source_finalize;
-
- signals[CHANGED_SIGNAL] =
- g_signal_new ("changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
-}
-
-ShellEvolutionEventSource *
-shell_evolution_event_source_new (void)
-{
- return SHELL_EVOLUTION_EVENT_SOURCE (g_object_new (SHELL_TYPE_EVOLUTION_EVENT_SOURCE, NULL));
-}
-
-void
-shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
- gint64 msec_begin,
- gint64 msec_end)
-{
- GDateTime *middle_utc, *middle;
-
- /* The CalendarClient type is a convenience wrapper on top of
- * Evolution Data Server. It is based on the assumption that only
- * a single month is shown at a time.
- *
- * To avoid reimplemting all the work already done in CalendarClient
- * we make the same assumption. This means that we only show events
- * in the month that is in the middle of @msec_begin and
- * @msec_end. Since the Shell displays a month at a time (plus the
- * days before and after) it works out just fine.
- */
-
- middle_utc = g_date_time_new_from_unix_utc ((msec_begin + msec_end) / 2 / 1000);
- /* CalendarClient uses localtime rather than UTC */
- middle = g_date_time_to_local (middle_utc);
- g_date_time_unref (middle_utc);
- g_date_time_get_ymd (middle, &source->req_year, &source->req_mon, NULL);
- g_date_time_unref (middle);
- calendar_client_select_month (source->client, source->req_mon - 1, source->req_year);
-}
-
-static gint
-event_cmp (gconstpointer a,
- gconstpointer b)
-{
- const ShellEvolutionEvent *ea;
- const ShellEvolutionEvent *eb;
-
- ea = a;
- eb = b;
- if (ea->msec_begin < eb->msec_begin)
- return -1;
- else if (ea->msec_begin > eb->msec_begin)
- return 1;
- else
- return 0;
-}
-
-/**
- * shell_evolution_event_source_get_events:
- * @source: A #ShellEvolutionEventSource.
- * @msec_begin: Start date (milli-seconds since Epoch).
- * @msec_end: End date (milli-seconds since Epoch).
- *
- * Gets all events that occur between @msec_begin and @msec_end.
- *
- * Returns: (element-type ShellEvolutionEvent) (transfer full): List of events.
- */
-GList *
-shell_evolution_event_source_get_events (ShellEvolutionEventSource *source,
- gint64 msec_begin,
- gint64 msec_end)
-{
- GList *result;
- GDateTime *cur_date;
- GDateTime *begin_date_utc, *begin_date;
- GDateTime *end_date_utc, *end_date;
-
- g_return_val_if_fail (msec_begin <= msec_end, NULL);
-
- result = NULL;
-
- begin_date_utc = g_date_time_new_from_unix_utc (msec_begin / 1000);
- end_date_utc = g_date_time_new_from_unix_utc (msec_end / 1000);
-
- /* CalendarClient uses localtime rather than UTC */
- begin_date = g_date_time_to_local (begin_date_utc);
- end_date = g_date_time_to_local (end_date_utc);
- g_date_time_unref (begin_date_utc);
- g_date_time_unref (end_date_utc);
-
- cur_date = g_date_time_ref (begin_date);
- do
- {
- gint year, mon, day;
- GDateTime *next_date;
-
- g_date_time_get_ymd (cur_date, &year, &mon, &day);
- /* g_print ("y=%04d m=%02d d=%02d\n", year, mon, day); */
-
- /* Silently drop events not in range (see comment in
- * shell_evolution_event_source_request_range() above)
- */
- if (!(year == source->req_year && mon == source->req_mon))
- {
- /* g_print ("skipping day\n"); */
- }
- else
- {
- GSList *events;
- GSList *l;
- calendar_client_select_day (source->client, day);
- events = calendar_client_get_events (source->client, CALENDAR_EVENT_APPOINTMENT);
- /* g_print ("num_events: %d\n", g_slist_length (events)); */
- for (l = events; l; l = l->next)
- {
- CalendarAppointment *appointment = l->data;
- ShellEvolutionEvent *event;
- gint64 start_time;
-
- if (appointment->is_all_day)
- {
- start_time = g_date_time_to_unix (cur_date) * G_GINT64_CONSTANT (1000);
- }
- else
- {
- start_time = appointment->start_time * G_GINT64_CONSTANT (1000);
- }
- event = shell_evolution_event_new (appointment->summary,
- appointment->is_all_day,
- start_time);
- result = g_list_prepend (result, event);
- }
- g_slist_foreach (events, (GFunc) calendar_event_free, NULL);
- g_slist_free (events);
- }
-
- next_date = g_date_time_add_days (cur_date, 1);
- g_date_time_unref (cur_date);
- cur_date = next_date;
- }
- while (g_date_time_difference (end_date, cur_date) > 0);
- g_date_time_unref (begin_date);
- g_date_time_unref (end_date);
-
- result = g_list_sort (result, event_cmp);
-
- return result;
-}
-
-G_DEFINE_BOXED_TYPE (ShellEvolutionEvent,
- shell_evolution_event,
- shell_evolution_event_copy,
- shell_evolution_event_free);
-
-void
-shell_evolution_event_free (ShellEvolutionEvent *event)
-{
- g_free (event->summary);
- g_free (event);
-}
-
-ShellEvolutionEvent *
-shell_evolution_event_copy (ShellEvolutionEvent *event)
-{
- ShellEvolutionEvent *copy;
- copy = g_memdup (event, sizeof (ShellEvolutionEvent));
- copy->summary = g_strdup (event->summary);
- return copy;
-}
-
-ShellEvolutionEvent *
-shell_evolution_event_new (const gchar *summary,
- gboolean all_day,
- gint64 msec_begin)
-{
- ShellEvolutionEvent *event;
- event = g_new0 (ShellEvolutionEvent, 1);
- event->summary = g_strdup (summary);
- event->all_day = all_day;
- event->msec_begin = msec_begin;
- return event;
-}
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-#ifndef __SHELL_EVOLUTION_EVENT_SOURCE_H__
-#define __SHELL_EVOLUTION_EVENT_SOURCE_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ShellEvolutionEvent ShellEvolutionEvent;
-
-struct _ShellEvolutionEvent
-{
- gchar *summary;
- gboolean all_day;
- gint64 msec_begin;
-};
-
-GType shell_evolution_event_get_type (void) G_GNUC_CONST;
-ShellEvolutionEvent *shell_evolution_event_new (const gchar *summary,
- gboolean all_day,
- gint64 msec_begin);
-ShellEvolutionEvent *shell_evolution_event_copy (ShellEvolutionEvent *event);
-void shell_evolution_event_free (ShellEvolutionEvent *event);
-
-typedef struct _ShellEvolutionEventSource ShellEvolutionEventSource;
-typedef struct _ShellEvolutionEventSourceClass ShellEvolutionEventSourceClass;
-
-#define SHELL_TYPE_EVOLUTION_EVENT_SOURCE (shell_evolution_event_source_get_type ())
-#define SHELL_EVOLUTION_EVENT_SOURCE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSource))
-#define SHELL_EVOLUTION_EVENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
-#define SHELL_IS_EVOLUTION_EVENT_SOURCE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
-#define SHELL_IS_EVOLUTION_EVENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
-#define SHELL_EVOLUTION_EVENT_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
-
-GType shell_evolution_event_source_get_type (void) G_GNUC_CONST;
-ShellEvolutionEventSource *shell_evolution_event_source_new (void);
-void shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
- gint64 msec_begin,
- gint64 msec_end);
-GList *shell_evolution_event_source_get_events (ShellEvolutionEventSource *source,
- gint64 msec_begin,
- gint64 msec_end);
-G_END_DECLS
-
-#endif /* __SHELL_EVOLUTION_EVENT_SOURCE_H__ */
shell_global_get_tp_contacts_cb,
callback, NULL, NULL);
}
+
+/**
+ * shell_global_launch_calendar_server:
+ * @global: The #ShellGlobal.
+ *
+ * Launch the gnome-shell-calendar-server helper.
+ */
+void
+shell_global_launch_calendar_server (ShellGlobal *global)
+{
+ const gchar *bin_dir;
+ gchar *calendar_server_exe;
+ GError *error;
+ gchar *argv[2];
+ gint child_standard_input;
+
+ /* launch calendar-server */
+ bin_dir = g_getenv ("GNOME_SHELL_BINDIR");
+ if (bin_dir != NULL)
+ calendar_server_exe = g_strdup_printf ("%s/gnome-shell-calendar-server", bin_dir);
+ else
+ calendar_server_exe = g_strdup_printf (GNOME_SHELL_LIBEXECDIR "/gnome-shell-calendar-server");
+
+ argv[0] = calendar_server_exe;
+ argv[1] = NULL;
+ error = NULL;
+ if (!g_spawn_async_with_pipes (NULL, /* working_directory */
+ argv,
+ NULL, /* envp */
+ 0, /* GSpawnFlags */
+ NULL, /* child_setup */
+ NULL, /* user_data */
+ NULL, /* GPid *child_pid */
+ &child_standard_input,
+ NULL, /* gint *stdout */
+ NULL, /* gint *stderr */
+ &error))
+ {
+ g_warning ("Error launching `%s': %s (%s %d)",
+ calendar_server_exe,
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ }
+ /* Note that gnome-shell-calendar-server exits whenever its stdin
+ * file descriptor is HUP'ed. This means that whenever the the shell
+ * process exits or is being replaced, the calendar server is also
+ * exits...and if the shell is being replaced, a new copy of the
+ * calendar server is launched...
+ */
+
+ g_free (calendar_server_exe);
+}
const TpContactFeature *features,
ShellGetTpContactCb callback);
+void shell_global_launch_calendar_server (ShellGlobal *global);
+
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */